Я чувствовал себя в мире с Posix после многолетнего опыта.
Затем я прочитал это сообщение от Линуса Торвальдса, около 2002 года:
int ret; do { ret = close(fd); } while(ret == -1 && errno != EBADF);
НЕТ.
Вышеуказанное
(a) не переносится
(b) не существующая практика
"Не переносимая" часть исходит из того, что (как указал кто-то out), потоковая среда, в которой ядро закрывает FD на ошибках, FD, возможно, был повторно использован (ядром) для какой-то другой поток, и закрытие FD во второй раз является ошибкой.
Не только цикл, пока EBADF
не переносится, но любой цикл из-за условия гонки, который я, вероятно, заметил бы, если бы я не "сделал мир", приняв такие вещи как должное.
Однако в реализации стандартной библиотеки GCC С++ basic_file_stdio.cc
мы имеем
do
__err = fclose(_M_cfile);
while (__err && errno == EINTR);
Основной целью этой библиотеки является Linux, но, похоже, она не воспринимает Linus.
Насколько я понял, EINTR
происходит только после блокировки системных вызовов, что подразумевает, что ядро получило запрос на освобождение дескриптора до начала любой работы, прерванной. Поэтому нет необходимости в цикле. Действительно, поведение сигнала SA_RESTART
не относится к close
и генерирует такой цикл по умолчанию, именно потому, что он небезопасен.
Это ошибка стандартной библиотеки, верно? В каждом файле, когда-либо закрытом приложением С++.
РЕДАКТИРОВАТЬ: Чтобы избежать чрезмерной тревоги, прежде чем какой-то гуру приходит с ответом, я должен отметить, что close
только кажется позволять блокироваться при определенных обстоятельствах, возможно, ни один из которых никогда не применяется к обычным файлам. Я не понимаю всех деталей, но вы не должны видеть EINTR
от close
, не выбрав что-либо fcntl
или setsockopt
. Тем не менее эта возможность делает общий код библиотеки более опасным.