Linux/C/C++:为什么使用串行/USB 上的阻塞或非阻塞读取

问题描述 投票:0回答:1

我正在使用 通过串行/USB (/dev/ttyACM0) 从设备读取()/写入() 终止文本字符串。

首先我用 write() 发送一个命令。

当使用阻塞模式(规范模式?)时,我只需调用 read() 并等待终止的数据字符串返回。 当使用非阻塞模式(非规范模式?)时,我创建一个循环并在等待数据字符串返回时执行 usleep() (以 ).

这两种方式都按预期工作,但我现在想知道为什么我应该使用其中一种?

就我而言,我需要完整获取的数据字符串才能在我的简单(无线程)程序的其余部分中继续,因此如果我使用阻塞或非阻塞调用似乎并不重要。

如果我的程序使用线程,那么获取数据的线程使用阻塞还是非阻塞似乎仍然不重要?

我能想到的唯一可以从使用非阻塞调用中受益的情况是,如果我正在接收可以部分处理的数据流。

或者在循环中使用 usleep() (或类似的东西)而不是进行阻塞调用有好处吗?

serial-port termios unistd.h
1个回答
0
投票

...我现在想知道为什么我应该使用其中之一?

您的问题被表述为阻塞模式与非阻塞模式之间的选择。您还可以将规范模式与阻塞模式相关联,将非规范模式与非阻塞模式相关联。
但规范模式与原始模式与阻塞模式与非阻塞模式是正交的。

请参阅 Linux 阻塞与非阻塞串行读取
因此,有四种方案需要考虑,但非阻塞模式通常被误用。

就我而言,我需要完整获取的数据字符串才能继续...

这并非您的情况所独有。
大多数二进制协议需要接收整个消息才能完成消息验证,例如计算校验和或 CRC。只有在消息经过验证(即消息包已完整接收)后才会处理消息。

规范模式与原始模式之间的选择通常取决于接收到的数据。也就是说,它是 (ASCII) 文本行吗?
如果接收到的数据不是用 EOL(行尾)字符分隔的 ASCII 编码文本,则规范模式本质上是不切实际的。 使用非规范模式时,不会以任何方式处理数据字节。这种不处理数据的情况对于其他外设来说是典型的。但这是使用(POSIX)串行终端时的一个重大决定/选择!

您的用户空间程序仅从 termios 缓冲区获取字节,并且从硬件中删除了多个内核层。
非阻塞系统调用通常会导致轮询系统缓冲区效率低下,并增加延迟,而不是使用内置的事件驱动系统调用。

内核已经在使用中断(也许还有 DMA)和事件驱动的处理程序来有效地处理接收到的数据。当接收到的数据满足串行终端的 termios 标准时,read() 系统调用将被解除阻塞,并通知调度程序该进程已准备好执行。

多处理操作系统依赖进程来共享可用的CPU。典型的过程预计是计算和 I/O 的混合。当执行 I/O 时,该进程不需要使用 CPU。执行该 I/O 的系统时间可以允许另一个进程使用 CPU。

但是,当进程使用非阻塞模式执行 I/O 时,它可以坚持保留对 CPU 的控制。该进程会占用 CPU,并降低系统的多处理效率。


一般来说,用户进程无法改进操作系统提供的阻塞模式的内置事件驱动方案。在循环中使用“

usleep()(或类似的东西)而不是进行阻塞调用

”,可以为已在内核空间中处理的操作添加更多在用户空间中的处理。非阻塞模式增加的复杂性通常会更慢且效率更低,并且永远不会更快或更高效。


我能想到的唯一可以从使用非阻塞调用中受益的情况是,如果我正在接收可以部分处理的数据流。

不,您将“
非阻塞调用

”与原始(或非规范)模式混淆了。原始模式使用 VMIN 和 VTIME 属性,允许控制 read() 返回的时间。 使用非阻塞模式的偶然和特殊原因可能包括:

进程/线程正在多个设备上执行并发 I/O;
  • 死连接需要能够被进程本身检测到;
  • 进程确实有事情要做,而且这个 I/O 和处理不能是单独的线程。
  • 否则,典型的程序很难证明不使用阻塞模式。

© www.soinside.com 2019 - 2024. All rights reserved.