Linux阻塞与非阻塞串行读取 [英] Linux Blocking vs. non Blocking Serial Read

查看:120
本文介绍了Linux阻塞与非阻塞串行读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

i have this code for reading from Serial in Linux , but i don't know what is the difference between blocking and non blocking in reading Serial Port and which one is better in which situation?

推荐答案

您提到的代码是IMO编码和注释不正确的代码.该代码不符合 POSIX操作系统串行编程指南.该代码没有提及它使用非规范(即原始)模式,而是重用阻塞"和非阻塞"术语来描述 VMIN VTIME 属性.

The code you mention is IMO poorly coded and commented. That code does not conform to POSIX practices for portability as described in Setting Terminal Modes Properly and Serial Programming Guide for POSIX Operating Systems. That code does not mention that it uses non-canonical (aka raw) mode, and reuses the "blocking" and "nonblocking" terminology to describe the VMIN and VTIME attributes.

(该代码的作者报告说,它早于POSIX标准,因此不合规.这是可以理解的,但是随后发布并提倡使用可能不可移植的旧代码(即,如预期的功能)另一种情况)是有问题的.)

(The author of that code reports that it predates the POSIX standard, and hence its non-compliance. That is understandable, but to then post and advocate the use of old code that may not be portable (i.e. function as expected in an alternate situation) is questionable.)

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

The conventional definition of a "blocking" versus "nonblocking" read is based on "when" the read call will return to your program (and resume execute with the next statement) and whether there will be data stored in your program's read buffer. A blocking read is the default mode, unless nonblocking is requested by opening the serial port with the O_NONBLOCK or O_NDELAY option.

规范模式
要进行
规范阅读的调用串行端口,将始终在提供的缓冲区中返回一行文本(即记录)(除非发生错误).只要需要接收和处理行终止符,read调用就会被阻塞(即暂停执行程序).

Canonical mode
For a blocking canonical read call of a serial port, a line (aka record) of text will always be returned in the provided buffer (unless an error occurred). The read call will block (i.e. suspend execution of your program) for as long as it takes for a line termination character to be received and processed.

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

A nonblocking canonical read call of a serial port will always return "immediately". The read may or may not return any data.
If (since the previous read call) at least a line of text has been received and stored in the system buffer, then the oldest line will be removed from the system buffer and copied to the program's buffer. The return code will indicate the data length.
If (since the previous read call) a line-termination character has not been received and processed, then there is no (complete) line of text available. The read() will return an EAGAIN error (i.e. a -1 return code and errno set to EAGAIN). Your program can then perform some calculation, or request I/O from another device, or delay/sleep. Either after an arbitrary delay or by notification by poll() or select(), your program can retry the read().

此答案.

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

Non-canonical mode
When the serial port is configured for non-canonical mode, the termios c_cc array elements VMIN and VTIME should be used to control "blocking", but this requires that the port be opened in the default blocking mode, i.e. do not specify the O_NONBLOCK open option. Otherwise O_NONBLOCK will have precedence over the VMIN and VTIME specification, and read() will set errno to EAGAIN and immediately return -1 instead of 0 when there is no data available. (This is the behavior observed in recent Linux 3.x kernels; older 2.6.x kernels may behave differently.)

termios手册页将( c_cc 数组索引) VMIN 描述为非规范读取的最小字符数" ,和( c_cc 数组索引) VTIME 作为非规范读取的超时时间(以分秒为单位)" .
VMIN 应该由您的程序进行调整,以适应预期的典型消息或数据报长度和/或数据的最小大小. read()处理.
VTIME 应该由您的程序进行调整,以适应预期的典型串行数据突发性或到达速率和/或等待数据或数据的最大时间.

The termios man page describes (c_cc array index) VMIN as the "minimum number of characters for noncanonical read", and (c_cc array index) VTIME as the "timeout in deciseconds for noncanonical read".
VMIN should be adjusted by your program to accommodate the typical message or datagram length that is expected and/or the minimum size for data to retrieve & process per read().
VTIME should be adjusted by your program to accommodate the typical burstiness or arrival rate of serial data that is expected and/or the maximum time to wait for data or a datum.

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

The VMIN and VTIME values interact to determine the criterion for when read should return; their precise meanings depend on which of them are nonzero. There are four possible cases.
This web page explains it as:

  • VMIN = 0且VTIME = 0

  • VMIN = 0 and VTIME = 0

这是一个完全非阻塞的读取-调用直接从驱动程序的输入队列中立即得到满足.如果有可用数据,则会将其传输到调用者的缓冲区(最大为nbytes)并返回.否则,立即返回零以指示无数据".我们将注意到这是对串行端口的轮询",这几乎总是一个坏主意.如果重复执行,则可能会消耗大量的处理器时间,并且效率极低.除非您真的非常了解自己在做什么,否则请不要使用此模式.

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

  • VMIN = 0 and VTIME > 0

    这是纯定时读取.如果输入队列中有可用数据,则将数据最多传输到调用者的缓冲区(最多nbytes),并立即返回给调用者.否则,驱动程序将阻塞,直到数据到达为止,或者从调用开始起VTIME十分之一过期.如果计时器在没有数据的情况下到期,则返回零.一个字节足以满足此读取调用,但是如果输入队列中有更多可用字节,则将其返回给调用方.请注意,这是一个整体计时器,而不是字符间计时器.

    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

  • VMIN > 0 and VTIME > 0

    当VMIN字符已转移到调用者的缓冲区中,或者当VTIME十分之一在字符之间到期时,将满足read()的要求.由于此计时器直到第一个字符到达时才启动,因此如果串行线路空闲,则此调用可以无限期地阻塞.这是最常见的操作模式,我们认为VTIME是字符间超时,而不是整体超时.该调用永远不要返回读取的零字节.

    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和x86上的Linux 3.13,以快速波特率(115200),在VMIN = 1和VTIME = 1的情况下,read()有时返回10个或更多字节. VTIME值.也许这种破坏是首选/理想的呢?在现代快速波特率下,最少0.1秒的消息间隔实在太长了(而且不切实际).

    (In my experience, the VMIN>0 and VTIME>0 mode doesn't quite work as advertised. The timer seems to be a very short interval, much less than a 1/10th second. I haven't seen it work on ARM with 2.6, and Linux 3.13 on x86. At a fast baudrate (115200), with VMIN=1 and VTIME=1, a read() sometimes returns 10 or more bytes. But more often it's just a partial read of a few bytes regardless of the VTIME value. Maybe this brokenness is preferred/desired? A minimum 0.1 sec message separation is simply too long (and not practical) at modern fast baudrates.)

    • VMIN> 0且VTIME = 0
    • VMIN > 0 and VTIME = 0

    这是一个计数读取,只有当至少VMIN字符已传输到调用者的缓冲区时才满足-不涉及计时组件.可以从驱动程序的输入队列(调用可以立即返回)中满足此读取要求,也可以通过等待新数据到达来满足此要求:在此方面,调用可以无限期地阻塞.我们认为,如果nbytes小于VMIN,则这是未定义的行为.

    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.

    That code you mention configures "nonblocking" mode as VMIN=0 and VTIME=5. This will not cause the read() to return immediately like a nonblocking canonical read would; with that code a read() should always wait at least a half second before returning. The conventional definition of a "nonblocking" is that your calling program is not preempted during the syscall and gets control back (almost) immediately. To get an (unconditional and) immediate return (for a non-canonical read), set VMIN=0 and VTIME=0.

    这篇关于Linux阻塞与非阻塞串行读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆