当前位置: 首页 > 面试题库 >

Linux阻塞与非阻塞串行读取

邬友樵
2023-03-14
问题内容

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


问题答案:

您提到的代码是IMO编码和注释不当的代码。该代码不符合POSIX的可移植性惯例,如正确设置终端模式和POSIX操作系统的串行编程指南中所述。该代码没有提到它使用非规范(也称为原始)模式,并且重用了“阻塞”和“非阻塞”术语来描述
VMINVTIME 属性。

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

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

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

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

非规范模式
将串行端口配置为非规范模式时,应使用 termios c_cc 数组元素 VMINVTIME
来控制“阻塞”,但这要求在默认阻塞模式下打开端口,即不要指定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 ,以适应预期的典型消息或数据报长度和/或每个 read() 检索和处理的数据的最小大小。您的程序应调整
VTIME 以适应预期的典型串行数据突发性或到达速率和/或等待数据或数据的最大时间。

VMINVTIME 值进行交互,以确定何时读应该返回的标准; 它们的确切含义取决于其中哪一个非零。有四种可能的情况。
该网页将其解释为:

  • VMIN = 0和VTIME = 0

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

  • VMIN = 0且VTIME> 0

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

  • VMIN> 0和VTIME> 0

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

(根据我的经验,该VMIN>0 and VTIME>0模式并不能像所宣传的那样正常工作。计时器似乎间隔很短,不到1/10秒。我还没有看到它在2.6的ARM和Linux
3.13上可以运行x86。在快速波特率(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。



 类似资料:
  • 问题内容: Java中是否有非阻塞文件读取API?如果不是,在C ++中构建一个并通过JNI从Java应用程序中调用它是否明智? 问题答案: 不,不扩展。 可能是因为并非所有的操作系​​统都支持它。 Windows确实如此,从理论上讲,您可以编写Windows特定的C ++库,并通过JNI进行调用,但是将其与集成是很多工作。 我宁愿有一个工作线程将文件内容复制到管道中,并在管道的另一端进行非阻塞读

  • 非阻塞 IO 仅对在 Servlet 和 Filter(2.3.3.3节定义的,“异步处理”)中的异步请求处理和升级处理(2.3.3.5节定义的,“升级处理”)有效。否则,当调用 ServletInputStream.setReadListener 或ServletOutputStream.setWriteListener 方法时将抛出IllegalStateException。为了支持在 Ser

  • Web 容器中的非阻塞请求处理有助于提高对改善 Web 容器可扩展性不断增加的需求,增加 Web 容器可同时处理请求的连接数量。servlet 容器的非阻塞 IO 允许开发人员在数据可用时读取数据或在数据可写时写数据。非阻塞 IO 仅对在 Servlet 和 Filter(2.3.3.3节定义的,“异步处理”)中的异步请求处理和升级处理(2.3.3.5节定义的,“升级处理”)有效。否则,当调用 S

  • 我完全混淆了,,。 哪个是阻塞,哪个不是? 我的意思是如果我使用父进程是否等待子进程返回/才继续执行。 如何影响这些调用?

  • 问题内容: 我在获取ncurses的getch()阻止时遇到了一些问题。默认操作似乎是非阻塞的(或者我错过了一些初始化)?我希望它可以像Windows中的getch()一样工作。我尝试了各种版本的 (并非同时全部)。如果可能的话,我宁愿不(明确地)使用any 。一个围绕残培环路(),检查特定的返回值是OK了。 问题答案: curses库是一揽子交易。如果不正确初始化库,您不能仅仅提出一个例程并希望

  • 问题内容: 有没有一种方法可以以非阻塞方式使用python的socket.accept()来简单地运行它,并让我检查它是否有任何新连接?我 真的 不想使用线程。谢谢。 问题答案: 您可能想要类似的东西(请参阅文档)。您提供了三个套接字列表:您要监视其可读性,可写性和错误状态的套接字。当新的客户端正在等待时,服务器套接字将是可读的。 该功能将一直阻塞,直到套接字状态之一改变为止。如果您不想永远阻塞,