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

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

问题描述

我有此代码 在 Linux 中从串行读取,但我不知道在读取串行端口时阻塞和非阻塞有什么区别,在哪种情况下哪个更好?

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 实践终端模式正确POSIX 操作系统串行编程指南.该代码没有提到它使用非规范(又名原始)模式,并重用了阻塞"模式.和非阻塞"用于描述 VMINVTIME 属性的术语.

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.)

阻塞"的传统定义与非阻塞"read基于when"read 调用将返回到您的程序(并使用下一条语句继续执行)以及是否将数据存储在您的程序的读取缓冲区中.阻塞读取是默认模式,除非通过使用 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 non-blocking is requested by opening the serial terminal with the O_NONBLOCK or O_NDELAY flag.

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

Canonical mode
For a blocking canonical read call of a serial terminal, 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 调用以来)尚未接收和处理行终止字符,则没有(完整的)文本行可用.read() 将返回一个 EAGAIN 错误(即 -1 返回码并且 errno 设置为 EAGAIN).然后您的程序可以执行一些计算,或从另一个设备请求 I/O,或延迟/睡眠.在任意延迟或通过 poll()select() 通知后,您的程序可以重试 read().

A nonblocking canonical read call of a serial terminal 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 terminal 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 terminal be opened in the default blocking mode, i.e. do not specify the O_NONBLOCK open flag.
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.

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

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

这是一个完全非阻塞的读取——直接从驱动程序的输入队列立即满足调用.如果数据可用,它会被传输到调用者的缓冲区,最多 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
  • 这是一个纯粹的定时阅读.如果输入队列中的数据可用,它会被传输到调用者的缓冲区,最多为 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 字符被传输到调用者的缓冲区时,或者当 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 和 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=1 时,VTIME 规范将无关紧要.任何数据的可用性将始终满足单个字节的最小标准,因此可以忽略时间标准(因为它将是具有非零 VMIN 的字符间时间规范).@IanAbbot 指出了这种特殊情况.

        Note when VMIN=1 that the VTIME specification will be irrelevant. The availability of any data will always satisfy the minimum criterion of a single byte, so the time criterion can be ignored (since it would be an intercharacter time specification with a nonzero VMIN). This special case was pointed out by @IanAbbot.

        您提到的代码配置了非阻塞";模式为 VMIN=0 和 VTIME=5.这不会像非阻塞规范读取那样导致 read() 立即返回;使用该代码, read() 应该在返回之前至少等待半秒.
        非阻塞"的传统定义如下:是您的调用程序在系统调用期间没有被抢占,并且(几乎)立即获得控制权.
        要获得(无条件和)立即返回(对于非规范读取),请设置 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 (with the attendant warnings).

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

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