Scroll to navigation

close(2) System Calls Manual close(2)

НАИМЕНОВАНИЕ

close - закрывает файловый дескриптор

БИБЛИОТЕКА

Стандартная библиотека C (libc, -lc)

ОБЗОР

#include <unistd.h>
int close(int fd);

ОПИСАНИЕ

Программа close() закрывает файловый дескриптор, так что он больше не ссылается ни на какой файл и может быть использован повторно. Любые блокировки записей (смотрите fcntl(2)), сохраненные в файле, с которым он был связан и которым владел процесс, удаляются независимо от файлового дескриптора, который использовался для получения блокировки. Это имеет некоторые печальные последствия и следует быть особенно осторожным при использовании рекомендуемой блокировки записей. Смотрите в fcntl(2) о рисках и последствиях, а также (вероятно, предпочтительных) блокировках дескрипторов открытых файлов.

Если fd является последним файловым дескриптором, ссылающимся на базовый дескриптор открытого файла (смотрите open(2), то ресурсы, связанные с дескриптором открытого файла, освобождаются; если файловый дескриптор был последней ссылкой на файл, удалённый с помощью unlink(2), то файл окончательно удаляется.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении программы close() возвращается 0. В случае ошибки возвращается -1, а значение errno указывает на ошибку.

ОШИБКИ

Значение fd не является допустимым дескриптором открытого файла.
Вызов close() был прерван по сигналу; смотрите signal(7).
Произошла ошибка ввода-вывода.
В NFS об этих ошибках, обычно, не сообщается при первой записи, которая превысила доступное пространство памяти, а только при последующих операциях write(), fsync(2) или close().

Смотрите ПРИМЕЧАНИЯ к обсуждению почему close() нельзя вызывать снова после ошибки.

СТАНДАРТЫ

POSIX.1-2008.

ИСТОРИЯ

POSIX.1-2001, SVr4, 4.3BSD.

ПРИМЕЧАНИЯ

Выполнение закрытия без ошибок не гарантирует, что данные были успешно записаны на диск, так как в ядре используется буферный кэш для отложенных записей. Как правило, файловые системы не записывают буферы при закрытии файла. Если требуется гарантировать физическую запись на используемый диск, то можно использовать fsync(2) (дальше всё будет зависеть от аппаратурных особенностей диска).

Флаг файлового дескриптора close-on-exec можно использовать для гарантии того, что файловый дескриптор автоматически закроется при успешном выполнении execve(2). Смотрите подробности в fcntl(2).

Многопоточные процессы и close()

Вероятно неблагоразумно закрывать дескрипторы файла, в то время как они могут использоваться системными вызовами других потоков того же процесса. Поскольку файловый дескриптор может использоваться повторно, то существуют некоторые неясные условия гонки, которые могут вызвать непреднамеренные побочные эффекты.

Кроме того, рассмотрим следующий сценарий, в котором два потока выполняют операции с одним и тем же файловым дескриптором:

(1)
Один поток блокируется при системном вызове ввода-вывода для файлового дескриптора. Например, он пытается выполнить write(2) (запись) в канал, который уже заполнен, или пытается выполнить read(2) (чтение) из потокового сокета, в котором в данный момент нет доступных данных.
(2)
Другой поток закрывает файловый дескриптор.

Поведение в этой ситуации различается в разных системах. В некоторых системах, когда файловый дескриптор закрыт, системный вызов блокировки немедленно возвращается с ошибкой.

В Linux (и, возможно, в некоторых других системах) поведение иное: системный вызов блокировки ввода-вывода содержит ссылку на дескриптор базового открытого файла и эта ссылка сохраняет дескриптор открытым до завершения системного вызова ввода-вывода (смотрите open(2) для обсуждения открытого файлового дескриптора). Таким образом, блокирующий системный вызов в первом потоке может успешно завершиться после close() во втором потоке.

Обработка ошибки, возвращённой close()

Аккуратный программист всегда проверяет возвращаемое close() значение, так как очень вероятно, что об ошибках предыдущей операции write(2) будет сообщено только при последнем вызове close(), который освобождает дескриптор открытого файла. Невыполнение проверки возвращаемого значение при закрытии файла может привести к silent (неучтённой) потере данных. Это особенно часто встречается с NFS и с дисковыми квотами.

Однако заметим, что возвращаемая ошибка должна использоваться только для диагностики (т. е. предупреждать приложение, что, возможно, есть незаконченные операции ввода-вывода или произошла ошибка ввода-вывода) или для исправления (например, повторной записи файла, или для создания резервной копии).

Повторный вызов close() после получения ошибки делать не стоит, так как это может привести к закрытию повторно использованного файлового дескриптора другого потока. Это может произойти из-за того, что ядро Linux always освобождает файловый дескриптор в самом начале операции закрытия, делая его доступным для повторного использования. Шаги, которые могут вернуть ошибку, такие как сброс данных в файловую систему или в устройство, происходят только после операции закрытия.

Многие другие реализации поступают схожим образом и всегда закрывают файловый дескриптор (за исключением случая EBADF, означающего некорректный файловый дескриптор) даже, если они затем возвратят ошибку close(). В POSIX.1 ничего не сказано на этот счёт, но есть планы узаконить такое поведение в следующем выпуске стандарта.

Аккуратный программист, который хочет узнать об ошибках ввода-вывода, перед вызовом close() вызовет fsync(2).

Ошибка EINTR является особым случаем. Об EINTR в POSIX.1-2008 сказано:

Если close() прерван сигналом, который будет обработан, то вызов должен вернуть -1, а errno присвоить значение EINTR; при этом состояние fildes не определено.

Этим допускается режим работы, действующий в Linux и многих других реализациях, где как и при других ошибках, которые может вернуть close(), файловый дескриптор гарантированно закрывается. Однако, это также допускает и другой режим: реализация возвращает ошибку EINTR и оставляет файловый дескриптор открытым (согласно документации, так делает close() в HP-UX). Затем вызывающая сторона должна еще раз использовать close(), чтобы закрыть файловый дескриптор, чтобы избежать утечки файлового дескриптора. Такое расхождение в поведении реализаций является сложным препятствием для переносимых приложений, так как во многих реализациях close() не должен вызываться ещё раз после получения ошибки EINTR и, по крайней мере, в одном случае необходимо снова вызвать программу close(). Есть планы разгадать эту загадку в следующей большой версии стандарта POSIX.1.

СМОТРИТЕ ТАКЖЕ

close_range(2), fcntl(2), fsync(2), open(2), shutdown(2), unlink(2), fclose(3)

ПЕРЕВОД

Русский перевод этой страницы руководства разработал(и) Dmitry Bolkhovskikh <d20052005@yandex.ru>, Yuri Kozlov <yuray@komyakino.ru> и Aleksandr Felda <isk8da@gmail.com>

Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков.

2024-05-02 Страницы руководства Linux 6.8