Приложение какое - многопоточное или все в одном процессе?
select() сработал - т е произошло событие на дескрипторе и не факт, что это данные. Может быть например ошибка
Если ты читаешь в raw mode, проверь, что у тебя в c_cc[VMIN] и c_cc[VTIME]. Детальней смотри в Serial Programming Guide
for POSIX Operating Systems
http://www.easysw.com/~mike/serial/serial.html в параграфе "Setting Read Timeouts".
Также это неплохо описано в книжке Linux Application Development
(Johnson, Troan), примеры оттуда есть в Инете свободно.
Наверное у Стивенса в тоже APUE было, но сейчас под рукой нету.
Ну и man termios в руки.
Если кратко:
1. если VTIME==0, read() блокируется, пока не будет доступно VMIN байт
2. если VMIN==0, read() вернется не позднее, чем через VTIME десятых
секунд и если ни фига не прочитано - вернет 0 (причем это не будет
означать EOF)
3. если VTIME!=0 и VMIN!=0 то ... не помню наизуть... что-то там
нетривиальное, прочитай сам
4. если VTIME==0 и VMIN==0 то read() в любом случае не блокирующий
и может вернуть 0 если нет данных.
Значит "слишком быстро работаешь". Поставь перед забором данных паузу и посмотри что будет. А также попробуй поменять на блокирующий и посмотреть тчо полчится.
> я ж писал НЕБЛОКИРУЮЩИЙ read(). Его НЕЛЬЗЯ сделать неблокирующим
> иначе как установив c_cc[VMIN]=0 и c_cc[VTIME]=0;
Конечно можно. Установив O_NONBLOCK для файл-дескриптора.
> изучил почти как "Отче Наш".
Чесслово - незаметно. Раз ты _сам_ установил VMIN=VTIME=0
то очевидно, read() _может_ вернуть 0.
> а если мне select() вернул что данные есть?????
Нет, ты не так понял select(). select() не сказал, что данные есть,
он лишь сказал, что ты можешь сделать read() и этот read() вернется
мгновенно, без блокировки. И это обещание он выполнил. Другое дело,
что ты так сконфигурировал драйвер терминального I/O (VTIME=VMIN=0),
что он рапортует о готовности к чтению даже при отсутствии данных
(и честно возвращает 0). Доступно?
Рекомендую попробовать так:
1. VMIN=1
2. VTIME=0
Теперь твой файл-дескриптор будет вести себя примерно так же,
как если бы это был pipe или там socket. То есть делай его
O_NONBLOCK, используй его в select() и так далее.
... давно это был... надеюсь, ничего не перепутал...
$ man 2 read
....
Three independent sets of descriptors are watched. Those listed in
readfds will be watched to see if characters become available for
reading (more precisely, to see if a read will not block...
...
Фтыкаем в слова "more precisely, to see if a read will not block"
до просветления ;-)
>... давно это был... надеюсь, ничего не перепутал...
перепутал.
>Конечно можно. Установив O_NONBLOCK для файл-дескриптора.
линукс на этот флаг ПОЛНОСТЬЮ забивает. что есть что нету а драйвер ком-порта смотрит только на VMIN и VTIME. кажись ман open || man fcntl.
>Раз ты _сам_ установил VMIN=VTIME=0 то очевидно, read() _может_ вернуть 0.
c этим никто не спорит. Вопрос не в этом.
>> а если мне select() вернул что данные есть?????
>Нет, ты не так понял select(). select() не сказал, что данные есть,
он лишь сказал, что ты можешь сделать read() и этот read() вернется
мгновенно, без блокировки. И это обещание он выполнил.
а что он мне тогда сказал если я его просил ничего другог мне не сообщать????
>Другое дело, что ты так сконфигурировал драйвер терминального I/O (VTIME=VMIN=0),
>что он рапортует о готовности к чтению даже при отсутствии данных
(и честно возвращает 0). Доступно?
кажись 100% враньё. VTIME, VMIN никаким образом не влияют на поведение select() только на read(). Select() сам неплохо знает как себя вести в конкретной ситуации.
>Фтыкаем в слова "more precisely, to see if a read will not block" до просветления ;-)
спасибо, как-то раньше я этого не замечал. Хотя описанная мною ситуация проявляется гдето один раз на несколько десятков тысяч селектов() при неопределённых обстоятельствах.
2 cvv:
> > Конечно можно. Установив O_NONBLOCK для файл-дескриптора.
> линукс на этот флаг ПОЛНОСТЬЮ забивает. что есть что нету а драйвер
> ком-порта смотрит только на VMIN и VTIME. кажись ман open || man
> fcntl.
Ржунимагу! То есть Linux не поддерживает O_NONBLOCK? Что, вообще
не поддерживает? Или только для terminal i/o?
Ладно, сейчас попробуем.
Для начала без O_NONBLOCK:
$ cat ttt.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#define BAUDRATE B38400
#define _POSIX_SOURCE 1
main()
{
int fd, c;
struct termios newtio;
fd = open("/dev/tty9", O_RDWR | O_NOCTTY);
if (fd <0) {perror("/dev/tty9"); exit(-1); }
printf("Opened...\n");
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 1;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW, &newtio);
while (1)
{
char buf[16];
int n = read(fd,buf,sizeof(buf));
if (n>=0) printf("read() returned %d\n", n);
else perror("read()");
}
}
$ make ttt
cc ttt.c -o ttt
$
$ ./ttt
Opened...
# теперь идем на /dev/tty9 и вводим несколько символов
read() returned 1
read() returned 1
read() returned 1
read() returned 1
^C
$
ОК, все как ожидалось - блокирующий ввод.
Теперь меняем
open("/dev/tty9", O_RDWR | O_NOCTTY);
на
open("/dev/tty9", O_RDWR | O_NOCTTY | O_NONBLOCK);
$ make ttt
cc ttt.c -o ttt
$ ./ttt
Opened...
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
read(): Resource temporarily unavailable
^C
$
Как видим, read() не блокируется, сплошным потоком посыпался вывод
от perror() с вполне логичным сообщением - "Resource temporarily
unavailable"
Ну и где же не работает O_NONBLOCK ?
Срочно иди учиться!
>Срочно иди учиться!
век живи - век учись
крайне странная ситуация:
man open:
O_NONBLOCK or O_NDELAY
This mode need not have any effect on files other than FIFOs.
то что на других системах он имеет эффект для ком-порта это мне известно, но чтобы он работал под линуксом первый раз вижу.
> крайне странная ситуация:
>
> man open:
> O_NONBLOCK or O_NDELAY
> This mode need not have any effect on files other than FIFOs.
>
> то что на других системах он имеет эффект для ком-порта это мне
> известно, но чтобы он работал под линуксом первый раз вижу.
"Не верь глазам своим!" (C)
Ну дык там и про сокеты ничего не написано, но ты же надеюсь
не сомневаешься, что для сокетов O_NONBLOCK работает ;-)
Скорее это объясняется тем, что поддержка O_NONBLOCK зависит от
конкретного типа файл-дескриптора, и man open не может перечислить
все возможные (и будущие) варианты дескрипторов (разные сокеты, пайпы,
devices...).
Если честно, то мой опыт в serial programming ограничивается UnixWare
и Solaris но было бы странно, если бы Linux отличался в
фундаментальных вещах типа интерпретации O_NONBLOCK.
> Именно O_NONBLOCK для сокета -- один из _немногих_ примеров, когда
> имеет смысл использовать неблокирующее _чтение_ совместно с select:
> Из man accept:
>
> To ensure that accept never blocks, the passed socket s needs to
> have the O_NONBLOCK flag set (see socket(7)).
>
Да, AFAIK это единственный случай, когда дескриптор, отмеченный
select()'ом как read-ready может оказаться не ready. Но я все
равно ставлю O_NONBLOCK для _всех_ дескрипторов, для которых I/O
регулируется select()'ом... это паранойя такая :-)))
BTW эта недоговорочка насчет O_NONBLOCK в Linux man open
наверное вызвана тем, что основной документацией должна
теперь быть info а на man'ы забили.
Попробовал вот из любопытства:
$ info open
...
-- Macro: int O_NONBLOCK
This prevents `open' from blocking for a "long time" to open the
file. This is only meaningful for some kinds of files, usually
devices such as serial ports; when it is not meaningful, it is
harmless and ignored. Often opening a port to a modem blocks
until the modem reports carrier detection; if `O_NONBLOCK' is
specified, `open' will return immediately without a carrier.
...
$
Вот тут "devices" и даже "serial ports" явно указаны.
> Но я все
равно ставлю O_NONBLOCK для _всех_ дескрипторов, для которых I/O
регулируется select()'ом... это паранойя такая :-)))
Кстати, зря.
Так тебе придется ВСЮ логику самому писАть. А, между тем, часто бывает достаточно
только иногда select()'ом read-дескрипторы проверять, а в транзакциях полагаться
на блокирующие свойства read().
write-дескрипторы, действительно, имеет смысл всегда делать неблокирующими.
Насчет man open я где-то читал (не помню, где) обсуждение.
Типа, выяснили, что эта строчка перекочевала из некоторого текста,
где она звучала в контексте того, что современные файловые системы
настолько быстры, что O_NONBLOCK там не имеет никакого смысла и поэтому игнорируется
для всего, кроме пайпов.
>> Но я все равно ставлю O_NONBLOCK для _всех_ дескрипторов, для
>> которых I/O регулируется select()'ом... это паранойя такая :-)))
> Так тебе придется ВСЮ логику самому писАть. А, между тем, часто
> бывает достаточно только иногда select()'ом read-дескрипторы
> проверять, а в транзакциях полагаться на блокирующие свойства
> read().
Ни фига не понял. Если я для каких-то дескрипторов спрашиваю
у select() "можно уже читать/писать?" это очевидно значит, что
я ни в коем случае не хочу блокировки read()/write(). Для этих
дескрипторов. Поэтому я ставлю O_NONBLOCK для них - хотя это
реально нужно только в случае accept(). Но я ставлю на всякий
случай.
Это не значит, что у меня в процессе _все_ дескрипторы O_NONBLOCK.
Я ж вроде русским языком написал - "ставлю O_NONBLOCK для _всех_ дескрипторов, для которых I/O регулируется select()ом".
А те дескрипторы, которые никакими select() не мониторятся -
те могут быть любыми и использоваться как угодно - хоть
блокирующими read()/write() а хоть и AIO.
BTW, а что такое "транзакции" в данном контексте?
> write-дескрипторы, действительно, имеет смысл всегда делать
> неблокирующими.
Тоже ниасилил. O_NONBLOCK действует и на запись, и на чтение.
Как ты себе представляешь сокет, у которого на запись стоит
O_NONBLOCK а на чтение - нет? :-/
Извиняюсь, я неявно перевел разговор с сокетов на дескрипторы вообще.
> Это не значит, что у меня в процессе _все_ дескрипторы O_NONBLOCK.
Я ж вроде русским языком написал - "ставлю O_NONBLOCK для _всех_ дескрипторов, для которых I/O
регулируется select()ом".
Ну, представь, что ты оперируешь блоками данных, которые к тебе через
пайп лезут. Каждый блок требует более одного read(). Если с другой стороны начали писАть,
то тебе нельзя отвлекаться на других, пока
весь блок не прочитаешь. Но, вообще говоря, одновременно к тебе могут
сразу много писателей постучаться.
Описанная ситуация у меня наиболее часто почему-то встречается, BTW.
Я слушаю select()'ом толпу блокирующих дескрипторов, а потом
форкаюсь (или в пул кидаю), и спокойно полагаюсь на блокирующий read().
> Тоже ниасилил. O_NONBLOCK действует и на запись, и на чтение.
Как ты себе представляешь сокет, у которого на запись стоит
O_NONBLOCK а на чтение - нет? :-/
> Описанная ситуация у меня наиболее часто почему-то встречается,
> BTW. Я слушаю select()'ом толпу блокирующих дескрипторов, а потом
> форкаюсь или в пул кидаю), и спокойно полагаюсь на блокирующий
> read().
>
Асилил :-) Да, при таком дизайне ты конечно прав в отношении
O_NONBLOCK. Но у этой модели есть ограничение в плане расширения возможных транспортов. То есть у тебя и транспортный тред (тот, где
select), и worker threads должны уметь работать с транспортным
объектом (файл-дескриптором). Этого достаточно, пока клиенты
не захотят испозьзовать не просто TCP, а скажем SSL/TLS или там
IBM MQ Series или X.25. Тогда ты устанешь модифицировать свои
worker threads, чтобы они это все умели читать/писать :-O
Поэтому удобно транспорты сделать как совершенно отдельные модули,
которые инкапсулируют всю работу с транспортом (и читают, и пишут,
и все остальное). С worker thread'ами они обмениваются данными неким
унифицированным образом, например через очереди. Короче, наверное
долгое использование ACE (http://www.cs.wustl.edu/~schmidt/ACE.html)
наложило на меня свой отпечаток - хочется все максимально разделить
и инкапсулировать :-)))