Есть ли способ сделать single read()
в неблокирующем режиме на канале / терминале / и т. Д., Как я могу сделать это на сокете с recv(MSG_DONTWAIT)
?
Причина, по которой мне это нужно, заключается в том, что я не могу найти никакой гарантии, что read()
в дескрипторе файла, возвращенном как готовый к чтению select()
или poll()
, будет не блоком.
Я знаю, что дескриптор файла может быть неблокирующим с помощью fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)
, но это изменит режим для этого файлового дескриптора глобально, а не только в вызывающем потоке / процессе.Например:
% perl -MFcntl=F_SETFL,F_GETFL,O_NONBLOCK -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) | O_NONBLOCK; select undef, undef, undef, undef'
^Z # put it in the background
% cat
cat: -: Resource temporarily unavailable
Это также сделает fd неблокирующим для и чтения и записи, что может запутать ад из другого процесса, выполняющего противоположное действие на том же самом fd, так какin:
non_blocking_read | filter | blocking_write
Один из способов, который я думаю, это сохранить флаги состояния файла при запуске и SIGCONT
и восстановить их при выходе и SIGTSTP
(так же, как это делается с помощью termiosнастройки), но это очень ограниченно, склонно к гонкам и оставит беспорядок в случае ненормального выхода из программы.
Установка сохранения / восстановления с помощью fcntl()
до / после каждого read()
также чувствует себя уродливым и тупым, и может иметь и другие проблемы.То же самое с ioctl(FIONREAD)
как раз перед read
(который я даже не уверен, что он будет надежно работать с любым fd; гарантии в этом направлении будут приветствоваться, хотя).
Я был бы счастливдаже с системными (например, linux или bsd-only) решениями.
Для справки здесь - это обсуждение исправления в linux;эта идея, похоже, никуда не делась.