系统相关
首页 > 系统相关> > Linux阻塞与非阻塞串行读取

Linux阻塞与非阻塞串行读取

作者:互联网

我有从Linux中的Serial读取this code,但我不知道在读取串口时阻塞和非阻塞有什么区别,哪一个在哪种情况下更好?

解决方法:

您提到的代码是IMO编码和评论不佳.该代码不符合POSIX实践中的可移植性,如Setting Terminal Modes ProperlySerial Programming Guide for POSIX Operating Systems中所述.该代码未提及它使用非规范(又称原始)模式,并重用“阻塞”和“非阻塞”术语来描述VMIN和VTIME属性.

(该代码的作者报告它早于POSIX标准,因此它不符合.这是可以理解的,但后来发布并提倡使用可能不可移植的旧代码(即在其他情况下按预期运行) )值得怀疑.)

“阻塞”与“非阻塞”读取的传统定义基于“何时”读取调用将返回到您的程序(并使用下一个语句继续执行)以及是否将数据存储在程序的读取缓冲区中.阻塞读取是默认模式,除非通过使用O_NONBLOCK或O_NDELAY选项打开串行端口来请求非阻塞.

规范模式
对于阻塞canonical read串行端口的调用,将始终在提供的缓冲区中返回文本行(也称为记录)(除非发生错误).只要接收和处理行终止字符,读取调用将阻止(即暂停程序的执行).

串行端口的非阻塞规范读取调用将始终“立即”返回.读取可能会也可能不会返回任何数据.
如果(自上次读取调用以来)至少接收到一行文本并将其存储在系统缓冲区中,则最旧的行将从系统缓冲区中删除并复制到程序的缓冲区中.返回码将指示数据长度.
如果(自上一次读取调用以来)尚未接收和处理行终止字符,则没有(完整的)文本行可用. read()将返回EAGAIN错误(即-1返回码和errno设置为EAGAIN).然后,您的程序可以执行某些计算,或从其他设备请求I / O,或延迟/休眠.在任意延迟之后或通过poll()或select()通知,您的程序可以重试read().

使用阻塞规范模式进行读取的示例程序包含在this answer中.

非规范模式
当串行端口配置为非规范模式时,应使用termios c_cc数组元素VMIN和VTIME来控制“阻塞”,但这需要以默认阻塞模式打开端口,即不要指定O_NONBLOCK打开选项.否则O_NONBLOCK将优先于VMIN和VTIME规范,read()将errno设置为EAGAIN,并在没有可用数据时立即返回-1而不是0. (这是在最近的Linux 3.x内核中观察到的行为;较旧的2.6.x内核可能表现不同.)

termios手册页将(c_cc数组索引)VMIN描述为“非规范读取的最小字符数”,并且(c_cc数组索引)VTIME描述为“非规范读取的以秒为单位的超时”.
VMIN应该由程序调整,以适应预期的典型消息或数据报长度和/或要检索的数据的最小大小.每次读取过程().
应通过程序调整VTIME,以适应预期的串行数据的典型突发性或到达率和/或等待数据或数据的最长时间.

VMIN和VTIME值相互作用以确定何时应返回读取的标准;它们的确切含义取决于它们中的哪一个非零.有四种可能的情况.
This web page解释为:

> VMIN = 0且VTIME = 0

This is a completely non-blocking read – the call is satisfied immediately directly from the driver’s input queue. If data are available, it’s transferred to the caller’s buffer up to nbytes and returned. Otherwise zero is immediately returned to indicate “no data”. We’ll note that this is “polling” of the serial port, and it’s almost always a bad idea. If done repeatedly, it can consume enormous amounts of processor time and is highly inefficient. Don’t use this mode unless you really, really know what you’re doing.

> VMIN = 0且VTIME> 0

This is a pure timed read. If data are available in the input queue, it’s transferred to the caller’s buffer up to a maximum of nbytes, and returned immediately to the caller. Otherwise the driver blocks until data arrives, or when VTIME tenths expire from the start of the call. If the timer expires without data, zero is returned. A single byte is sufficient to satisfy this read call, but if more is available in the input queue, it’s returned to the caller. Note that this is an overall timer, not an intercharacter one.

> VMIN> 0和VTIME> 0

A read() is satisfied when either VMIN characters have been transferred to the caller’s buffer, or when VTIME tenths expire between characters. Since this timer is not started until the first character arrives, this call can block indefinitely if the serial line is idle. This is the most common mode of operation, and we consider VTIME to be an intercharacter timeout, not an overall one. This call should never return zero bytes read.

(根据我的经验,VMIN> 0和VTIME> 0模式并不像宣传的那样工作.计时器似乎是一个非常短的间隔,远小于1/10秒.我还没有看到它在ARM上运行在x86上使用2.6和Linux 3.13.在快速波特率(115200),VMIN = 1且VTIME = 1时,read()有时返回10个或更多字节.但更常见的是它只是部分读取几个字节而不管VTIME值.也许这种破坏是首选/期望​​的?在现代快速波特率下,最小0.1秒的消息分离太长(而且不实用).)

> VMIN> 0和VTIME = 0

This is a counted read that is satisfied only when at least VMIN characters have been transferred to the caller’s buffer – there is no timing component involved. This read can be satisfied from the driver’s input queue (where the call could return immediately), or by waiting for new data to arrive: in this respect the call could block indefinitely. We believe that it’s undefined behavior if nbytes is less then VMIN.

您提到的代码将“非阻塞”模式配置为VMIN = 0且VTIME = 5.这不会导致read()立即返回,就像非阻塞规范读取一样;使用该代码,read()应该总是在返回之前等待至少半秒. “非阻塞”的传统定义是,您的调用程序在系统调用期间不会被抢占,并且(几乎)立即获得控制权.
要获得(无条件和)立即返回(对于非规范读取),请设置VMIN = 0和VTIME = 0.

标签:linux,nonblocking,serial-port,blocking
来源: https://codeday.me/bug/20190915/1804987.html