Блокировка Linux против неблокирующего последовательного чтения

Я код для чтения из последовательного в Linux, но я не знаю, в чем разница между блокировкой и неблокированием при чтении последовательного порта и какой из них лучше в какой ситуации?

1 ответов


код, который вы упоминаете, ИМО плохо закодирован и прокомментирован. Этот код не соответствует практике POSIX для переносимости, как описано в Настройка Режимов Терминала Правильно и руководство по последовательному программированию для операционных систем POSIX. Этот код не упоминает, что он использует неканонический (он же raw) режим и повторно использует терминологию" блокировка "и" неблокирующий " для описания VMIN и исключением vTime атрибуты.

в обычное определение" блокировки "по сравнению с" неблокирующим "чтением основано на" когда " вызов чтения вернется в вашу программу (и возобновит выполнение со следующим оператором) и будут ли данные сохранены в буфере чтения вашей программы. Блокирующее чтение-это режим по умолчанию, если не требуется неблокирующее открытие последовательного порта с помощью опции O_NONBLOCK или O_NDELAY.

каноническом режиме
Для блокировки каноническое чтение вызов a последовательный порт, строка (aka запись) текста всегда будет возвращена в предоставленном буфере (если не произошла ошибка). Вызов read будет блокировать (т. е. приостанавливать выполнение вашей программы) до тех пор, пока не будет получен и обработан символ завершения строки.

неблокирующий канонический вызов чтения последовательного порта всегда будет возвращать "немедленно". Чтение может возвращать или не возвращать какие-либо данные.
Если (с момента предыдущего вызова чтения) по крайней мере строка текста была полученная и сохраненная в системном буфере, самая старая строка будет удалена из системного буфера и скопирована в буфер программы. Код возврата будет указывать длину данных.
Если (с момента предыдущего вызова чтения) символ завершения строки не был получен и обработан, то (полная) строка текста недоступна. The прочитать() вернет ошибку EAGAIN (т. е. код возврата -1 и errno установить в EAGAIN). Ваш затем программа может выполнить некоторые вычисления или запросить ввод-вывод с другого устройства или задержку/сон. Либо после произвольной задержки, либо по уведомлению () или select () ваша программа может повторить прочитать().

неканонический режим
Когда последовательный порт настроен для неканонического режима,termios c_cc элементы массива VMIN и исключением vTime должно использоваться для управления "блокировкой", но для этого требуется, чтобы порт был открыт в режиме блокировки по умолчанию, т. е. не указывайте опцию o_nonblock open. В противном случае O_NONBLOCK будет иметь приоритет над спецификацией VMIN и VTIME и прочитать() устанавливается errno в EAGAIN и немедленно вернуть -1 вместо 0, когда нет доступных данных. (Это поведение наблюдается в недавнем Linux 3.х ядер; старше 2.6.икс ядра могут вести себя по-разному.)

страница руководства termios описывает (c_cc индекс массива) VMIN как "минимальное количество символов для неканонического чтения" и (c_cc индекс массива) исключением vTime как "время ожидания в deciseconds для неканонического чтения".
VMIN должно быть отрегулировано вашей программой для того чтобы приспособить типичную длину сообщения или дейтаграммы которая предположена и / или минимальный размер данных для извлечения и обработки в прочитать().
исключением vTime должно быть отрегулировано вашей программой для того чтобы приспособить типичные burstiness или тариф прибытия серийных данных которые предположены и/или максимальное время ждать данные или datum.

на VMIN и исключением vTime значения взаимодействуют для определения критерия, когда чтение должно вернуться; их точные значения зависят от того, какой из них ненулевой. Их четыре возможный случай.
этой странице объясняет это так:

  • VMIN = 0 и VTIME = 0

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

  • VMIN = 0 и VTIME > 0

    это чистое приуроченное чтение. Если данные доступны во входной очереди, они передаются в буфер вызывающего абонента до максимума nbytes и немедленно возвращаются вызывающему абоненту. В противном случае драйвер блокируется до данные поступают, или когда vTime десятых истекает с начала вызова. Если таймер истекает без данных, возвращается ноль. Одного байта достаточно для удовлетворения этого вызова чтения, но если во входной очереди доступно больше, он возвращается вызывающему. Обратите внимание, что это общий таймер, а не символами один.

  • VMIN > 0 и VTIME > 0

    a read () удовлетворяется, когда либо символы VMIN были переданы в буфер вызывающего абонента, или когда vTime десятых истекает между символами. Поскольку этот таймер не запускается до прибытия первого символа, этот вызов может блокировать бесконечно, если последовательная линия простаивает. Это наиболее распространенный режим работы, и мы считаем исключением vTime быть символами тайм-аут, а не в целом одна. Этот вызов никогда не должен возвращать чтение нулевых байтов.

(по моему опыту,VMIN>0 and VTIME>0 режим не совсем работает, как рекламируется. Таймер кажется быть очень коротким интервалом, намного меньше 1/10 секунды. Я не видел, чтобы он работал на ARM с 2.6 и Linux 3.13 на x86. При быстром baudrate (115200), с VMIN=1 и VTIME=1, read () иногда возвращает 10 или более байтов. Но чаще это просто частичное чтение нескольких байтов независимо от значения VTIME. Может быть, эта сломанность предпочтительна / желательна? Минимум 0.1 сек отделения сообщение просто слишком долго (а не практической) на современных быстрых скоростях.)

  • VMIN > 0 и Исключением vTime = 0

    это считанное чтение, которое выполняется только тогда, когда по крайней мере символы VMIN были переданы в буфер вызывающего абонента - нет компонента синхронизации. Это чтение может быть удовлетворено из входной очереди водителя (где вызов может вернуться немедленно) или ожиданием поступления новых данных: в этом отношении вызов может блокировать бесконечно. Мы считаем, что это неопределенное поведение, если nbytes меньше VMIN.

этот код, который вы упомянули, настраивает режим "неблокирующий" как VMIN=0 и VTIME=5. Это не приведет к тому, что read() вернется немедленно, как неблокирующее каноническое чтение; с этим кодом read() всегда должен ждать по крайней мере полсекунды перед возвращением. Обычное определение "неблокирующего" заключается в том, что ваша вызывающая программа не прерывается во время syscall и получает контроль (почти) немедленно. Чтобы получить (безусловное и) немедленный возврат (для неканонического чтения), установите VMIN=0 и VTIME=0.