Что делать, если вызов close закрыть не удается?

В моей системе (Ubuntu Linux, glibc) man-страница вызова close указывает несколько возвращаемых значений ошибки, которые она может вернуть. Он также говорит

Не проверять возвращаемое значение close() является общей, но тем не менее серьезной ошибкой программирования.

и в то же время

Обратите внимание, что возвращаемое значение должно использоваться только для диагностики. В частности, close() не следует повторять после EINTR, поскольку это может привести к закрытию повторно используемого дескриптора из другого потока.

Поэтому мне не разрешено игнорировать возвращаемое значение или повторить вызов.

Учитывая, что я должен обрабатывать отказ вызова close()?

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

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

Ответ 1

На практике close никогда не следует повторять при ошибке, а fd, который вы передали в close, всегда недействителен (закрыт) после возврата close, независимо от того, произошла ли ошибка. В некоторых случаях ошибка может указывать на то, что данные были потеряны (некоторые настройки NFS) или необычные аппаратные условия для устройств (например, лента не может быть перемотана), поэтому вы можете быть осторожны, чтобы избежать потери данных, но вы никогда не должны пытаться снова закройте fd.

В теории POSIX в прошлом было неясно, остается ли fd открытым, когда close терпит неудачу с EINTR, и системы не согласны. Поскольку важно знать состояние (в противном случае у вас есть либо fd-утечки, либо ошибки с двойным закрытием, которые чрезвычайно опасны в многопоточных программах), разрешение проблема с Austin Group # 529 указано поведение строго для будущих версий POSIX, что EINTR означает, что fd остается открытым. Это правильное поведение, совместимое с определением EINTR в другом месте, но Linux отказывается его принять. (FWIW там есть простой способ обхода, который возможен на уровне обертки libc syscall, см. glibc PR # 14627.) К счастью, это никогда не возникает на практике в любом случае.

Некоторые связанные вопросы, которые могут вам показаться информативными:

Ответ 2

Прежде всего: EINTR означает, что: Системный вызов был прерван, если это происходит при вызове close(), вы ничего не можете сделать.

Помимо того, что, возможно, отслеживая факт, что если fd принадлежит файлу, этот файл, возможно, поврежден, вы почти ничего не можете сделать об ошибках на close() - в зависимости от возвращаемого значения. AFAIK единственный случай, когда закрытие можно повторить, находится на EBUSY, но я еще этого не вижу.

Итак:

  • Не проверка результата close() может означать, что вы пропустите повреждение файла, особенно усечение.
  • В зависимости от ошибки большую часть времени вы ничего не можете сделать - сбой close() просто означает, что что-то ужасно ошибочно выходит за рамки вашего приложения.