CLOSE(2) | Руководство программиста Linux | CLOSE(2) |
close - закрывает файловый дескриптор
#include <unistd.h>
int close(int fd);
Функция close() закрывает файловый дескриптор, который после этого не ссылается ни на один и файл и может быть использован повторно. Все блокировки (см. fcntl(2)), связанные с соответствующим файлом и принадлежащие процессу, снимаются (независимо от того, какой файловый дескриптор был ли использован для установки блокировки).
Если fd является последней копией какого-либо файлового дескриптора, ссылающегося на используемое описание открытого файла, (см. open(2)), то ресурсы, связанные с описанием открытого файла, освобождаются; если файловый дескриптор был последней ссылкой на файл, удалённый с помощью unlink(2), то файл окончательно удаляется.
При успешном выполнении функции close() возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.
Смотрите в ЗАМЕЧАНИЯХ почему close() нельзя вызывать снова после ошибки.
POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.
Выполнение закрытия без ошибок не гарантирует, что данные были успешно записаны на диск, так как в ядре используется буферный кэш для отложенных записей. Как правило, файловые системы не записывают буферы при закрытии файла. Если требуется гарантировать физическую запись на используемый диск, то можно использовать fsync(2) (дальше всё будет зависеть от аппаратной составляющей диска).
Флаг файлового дескриптора закрытие-при-exec можно использовать для гарантии того, что файловый дескриптор автоматически закроется при успешном выполнении execve(2); подробности смотрите в fcntl(2).
Вероятно неблагоразумно закрывать дескрипторы файла, в то время как они могут использоваться системными вызовами других нитей того же процесса. Так как файловый дескриптор может использоваться повторно, есть некоторые неясные условия возникновения гонок, которые могут вызвать непреднамеренные побочные эффекты.
Аккуратный программист всегда проверяет возвращаемое close() значение, так как очень вероятно, что об ошибках предыдущей операции write(2) будет сообщено только при последнем вызове close(), который освобождает описание открытого файла. Невыполнение проверки возвращаемого значение при закрытии файла может привести к неучтённой потере данных. Это особенно часто встречается с NFS и дисковыми квотами.
Однако заметим, что возвращаемая ошибка должна использоваться только для диагностики (т. е., предупредить приложение, что, возможно, есть незаконченные операции ввода-вывода или произошла ошибка ввода-вывода) или исправления (например, повторной записи файла или создания резервной копии).
Повторный вызов close() после получения ошибки делать не стоит, так как это может привести к закрытию повторно использованного файлового дескриптора другой нити. Это может произойти из-за того, что ядро Linux всегда освобождает файловый дескриптор в самом начале операции закрытия, делая его доступным для повторного использования; шаги, которые могут вернуть ошибку, такие как сброс данных в файловую систему или устройство, происходят только после операции закрытия.
Многие другие реализации поступают схожим образом и всегда закрывают файловый дескриптор (за исключением случая EBADF, означающего некорректный файловый дескриптор) даже, если они затем возвратят ошибку close(). В POSIX.1 ничего не сказано на этот счёт, но есть планы узаконить такое поведение в следующем выпуске стандарта.
Аккуратный программист, который хочет узнать об ошибках ввода-вывода, перед close() вызовет fsync(2).
Ошибка EINTR является особым случаем. Про EINTR в POSIX.1-2013 сказано:
Этим допускается режим работы, действующий в Linux и многих других реализациях, где как и при других ошибках, которые может вернуть close(), файловый дескриптор гарантированно закрывается. Однако, это также допускает и другой режим: реализация возвращает ошибку EINTR и оставляет файловый дескриптор открытым (согласно документации, так делает close() в HP-UX). Вызывающий должен позднее ещё раз вызвать close() для закрытия файлового дескриптора, чтобы не допустить утечек файловых дескрипторов. Такое расхождение в поведении реализаций является сложным препятствием для переносимых приложений, так как во многих реализациях close() не должен вызываться ещё раз после получения ошибки EINTR и, по крайней мере, в одной close() нужно вызвать снова. Есть планы разгадать эту загадку в следующей большой версии стандарта POSIX.1.
fcntl(2), fsync(2), open(2), shutdown(2), unlink(2), fclose(3)
2017-09-15 | Linux |