C ++ стандартный ввод / вывод и сигналы - PullRequest
6 голосов
/ 11 июня 2019

Если я вызываю функцию POSIX, такую ​​как read(), которая не является частью стандартной библиотеки C ++, я должен беспокоиться о том, что она будет прервана сигналом, и обработать возвращаемое значение EINTR. Если я вызываю стандартную библиотечную функцию C ++, такую ​​как fread(), основанную на этой документации , то нет упоминания о EINTR, поэтому стандартная библиотека скрывает это от пользователя. Правильно ли мое понимание и верно ли это для всех стандартных библиотечных функций C ++?

Обновление: так что из ответов еще неясно, что это вывод о том, что нельзя написать стандартный C ++, который должным образом функционирует на каждой платформе? Я вижу, как люди упоминают о поведении POSIX, которое не является частью стандарта, так что это сбивает с толку.

Ответы [ 3 ]

3 голосов
/ 11 июня 2019

Если я вызываю функцию POSIX, такую ​​как read(), которая не является частью стандартной библиотеки C ++, я должен беспокоиться о том, что она прерывается сигналом, и обрабатывать возвращаемое значение EINTR.

И это не должно быть проблемой для вашего кода, потому что:

  1. read может завершиться ошибкой, поэтому возвращаемое значение и errno должны быть обработаны в любом случае.
  2. read может выполнять частичное чтение, поэтому в режиме блокировки вы должны вызывать read в цикле.errno == EINTR - это просто еще одно условие для повторной попытки вызова как в режиме блокировки, так и в режиме без блокировки.
1 голос
/ 11 июня 2019

POSIX охватывает также fread, что хорошо, так как стандарты C и C ++ очень мало говорят о сигналах для поддержки больше, чем просто POSIX. Он говорит, частично на странице fgetc, что fread может вернуться рано (возможно, возвращая 0), установить ferror и установить errno на EINTR. Конечно, если сигнал вызывает короткое read, у библиотеки C нет возможности обнаружить это, и она просто снова вызовет read, поэтому вы не можете рассчитывать на своевременный ответ на сигнал. Письмо аналогично.

В стандартной библиотеке C ++ очень мало других операций, которые могут выдавать EINTR; к сожалению, POSIX не распространяется на C ++, поэтому нет определенного ответа на такие вещи, как sleep_for, которых нет в C.

0 голосов
/ 14 июня 2019

fread() изначально был частью стандартной библиотеки C, libc, определенной в <stdio.h>.Стандартная библиотека C ++ делает то же самое fread() доступным через оболочку библиотеки C <cstdio>.

read() не имеет такой оболочки (возможно, потому что она конфликтует с версией istream), но вы можетепо-прежнему вызывать его с помощью библиотеки C.Вы правы, что read() взято из специфического для POSIX расширения <unistd.h> и не является частью стандартной библиотеки, но с тех пор оно реализовано довольно широко и часто распространяется с libc.

Вы также правы, что read() установит errno при сбое, и одна из этих ошибок может быть EINTR.А с другой стороны, когда fread() терпит неудачу, не может выяснить, какая ошибка произошла, так что технически вы также правы, что в этом случае вхождения EINTR скрыты от пользователя.Действительно, то, как fread() обрабатывает любые специфичные для платформы детали, зависит от реализации.Но было бы натяжкой сказать, что этот шаблон применяется ко «всем стандартным библиотечным функциям C ++» - вам действительно нужно проверять каждый случай отдельно.

Если вы хотите написать «правильно работающий» код, который выполняетсяна каждой платформе, тогда не используйте расширения POSIX.Придерживайтесь fread() и друзей и принимайте тот факт, что обобщение между платформами означает, что вы не сможете получить конкретные сведения о платформе, такие как номера ошибок.Поскольку возможные ошибки зависят от платформы, нет общего способа узнать, следует ли вам повторить попытку.

Более подробная информация о различиях между read() и fread() приведена здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...