linux - Linux阻塞与非阻塞串行读取

标签 linux serial-port blocking nonblocking termios

我有this code可以在Linux中从Serial读取,但是我不知道在读取Serial Port时阻塞和非阻塞之间有什么区别,在哪种情况下哪个更好?

最佳答案

您提到的代码是IMO编码和注释不正确的代码。该代码不符合Setting Terminal Modes ProperlySerial Programming Guide for POSIX Operating Systems中描述的可移植性POSIX惯例。该代码没有提到它使用非规范(即原始)模式,并重用了“阻塞”和“非阻塞”术语来描述 VMIN VTIME 属性。

(该代码的作者报告说,它早于POSIX标准,因此不合规。这是可以理解的,但此后应发布并提倡使用可能无法移植的旧代码(即,在替代情况下按预期的功能使用) )是有问题的。)

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

规范模式
对于阻塞的canonical read串行端口调用,将始终在提供的缓冲区中返回一行文本(即记录)(除非发生错误)。只要需要接收和处理行终止符,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手册页将 VMIN 描述为( c_cc 数组索引),将 VMIN 描述为“非规范读取的最小字符数”,将( c_cc 数组索引) VTIME 描述为“以秒为单位的超时读超时”。
VMIN 应该由您的程序进行调整,以适应预期的典型消息或数据报长度和/或每个 read()检索和处理的数据的最小大小。
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 and VTIME>0模式不能像所宣传的那样工作。计时器似乎间隔很短,不到1/10秒。我还没有看到它在ARM 2.6和Linux 3.13上运行在x86上,以快速波特率(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()应该始终等待至少半秒钟再返回。传统的“非阻塞”定义是,在syscall期间不会抢占您的调用程序,而是立即(几乎)将控制权收回。
    要获得(无条件和)立即返回(用于非规范读取),请设置VMIN = 0和VTIME = 0。

    关于linux - Linux阻塞与非阻塞串行读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25996171/

    相关文章:

    python - DMM、Python 和串口 : During a loop - the communication is suddenly stops

    c - 在 C 中通过 TCP 通信,如何在不知道有关数据的任何先验信息的情况下指示停止为请求调用 read()?

    tcp - 简单的 Rust TCP 服务器和客户端不接收消息并且永不终止

    linux - 重命名文件的shell脚本

    linux - 有没有办法从 tty 设备中查看值

    visual-studio-2010 - 使用Visual Studio 2010和C的串行通信(用于Arduino)

    ajax - Firefox HTTP 连接在阻塞阶段花费大量时间

    linux - TCP 套接字挂起 - 双方都卡在 sendto()

    python脚本进程stat停留在Sl上并停止运行

    c++ - 如何将 int 转换为 char(不是 const char)以便与 putChar() 一起使用;