Linux 阻塞与非阻塞串行读取
- 2024-09-30 15:23:00
- admin 原创
- 116
问题描述:
我有这个用于在 Linux 中从串行读取的代码,但我不知道在读取串行端口时阻塞和非阻塞之间有什么区别,以及在哪种情况下哪一个更好?
解决方案 1:
在我看来,您提到的代码编码和注释都很糟糕。该代码不符合 POSIX 可移植性实践,如正确设置终端模式和POSIX 操作系统串行编程指南中所述。该代码没有提到它使用非规范(又称原始)模式,并重用“阻塞”和“非阻塞”术语来描述VMIN和VTIME属性。
(该代码的作者报告说它早于 POSIX 标准,因此不符合要求。这是可以理解的,但随后发布并提倡使用可能不可移植的旧代码(即在其他情况下无法按预期运行)是值得怀疑的。)
“阻塞”与“非阻塞”读取的传统定义基于读取调用“何时”返回到您的程序(并使用下一个语句恢复执行)以及程序的读取缓冲区中是否会存储数据。阻塞读取是默认模式,除非通过使用 O_NONBLOCK 或 O_NDELAY 标志打开串行终端来请求非阻塞。
规范模式
对于串行终端的阻塞规范读取调用,一行(又称记录)文本将始终返回到提供的缓冲区中(除非发生错误)。读取调用将阻塞(即暂停执行程序),直到收到并处理行终止符为止。
串行终端的非阻塞标准读取调用将始终“立即”返回。读取可能会或可能不会返回任何数据。
如果(自上次读取调用以来)至少已收到一行文本并将其存储在系统缓冲区中,则将从系统缓冲区中删除最旧的行并将其复制到程序的缓冲区中。返回代码将指示数据长度。如果
(自上次读取调用以来)尚未收到和处理行终止符,则没有可用的(完整)文本行。read ()将返回 EAGAIN 错误(即 -1 返回代码和errno设置为 EAGAIN)。然后,您的程序可以执行一些计算,或从另一个设备请求 I/O,或者延迟/休眠。在任意延迟后或通过poll()或select()通知,您的程序可以重试read()。
该答案中包含一个使用阻塞规范模式进行读取的示例程序。
非规范模式
当串行终端配置为非规范模式时,应使用termios c_cc数组元素VMIN和VTIME
来控制“阻塞”,但这要求终端以默认阻塞模式打开,即不指定 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以适应预期的典型消息或数据报长度和/或每次读取 ()检索和处理的数据的最小大小。程序应调整
VTIME以适应预期的典型串行数据突发性或到达率和/或等待数据或基准的最大时间。
VMIN和VTIME值相互作用以确定read 应何时返回的标准;它们的确切含义取决于其中哪些是非零的。有四种可能的情况。此网页对此进行了解释:
VMIN = 0 且 VTIME = 0
这是一个完全非阻塞的读取 - 调用会立即从驱动程序的输入队列直接得到满足。如果有数据,则将其传输到调用者的缓冲区(最多 n 个字节)并返回。否则会立即返回零以表示“无数据”。我们会注意到,这是串行端口的“轮询”,这几乎总是一个坏主意。如果反复执行,它会消耗大量的处理器时间并且效率极低。除非您真的非常清楚自己在做什么,否则不要使用此模式。
VMIN = 0 且 VTIME > 0
这是一个纯定时读取。如果输入队列中有数据,则将数据传输到调用者的缓冲区(最多 n 个字节),并立即返回给调用者。否则,驱动程序将阻塞,直到数据到达,或者从调用开始到 VTIME 十分之一到期。如果计时器到期而没有数据,则返回零。单个字节足以满足此读取调用,但如果输入队列中有更多可用数据,则将其返回给调用者。请注意,这是一个整体计时器,而不是字符间计时器。
[警告:VMIN = 0 且 VTIME > 0 是超时读取,而不是定时读取。此读取不会等待VTIME 持续时间然后返回可用内容。只有在没有可用字符时才会发生超时。否则,只要有字符可用,读取就会立即返回。]
VMIN > 0 且 VTIME > 0
当 VMIN 个字符已传输到调用者的缓冲区,或者 VTIME 在字符之间十分之一到期时,read() 得到满足。由于此计时器直到第一个字符到达才启动,因此如果串行线路空闲,此调用可能会无限期阻塞。这是最常见的操作模式,我们认为 VTIME 是字符间超时,而不是整体超时。此调用绝不会返回零字节读取。
VMIN > 0 且 VTIME = 0
这是一个计数读取,只有当至少 VMIN 个字符已传输到调用者的缓冲区时才会满足 - 不涉及计时组件。此读取可以从驱动程序的输入队列(调用可以立即返回)中满足,或者通过等待新数据到达来满足:在这方面,调用可能会无限期阻塞。我们认为,如果 nbytes 小于 VMIN,则这是未定义的行为。
请注意,当 VMIN=1 时,VTIME 规范将变得无关紧要。任何数据的可用性始终满足单个字节的最小标准,因此可以忽略时间标准(因为它将是具有非零 VMIN 的字符间时间规范)。@IanAbbot 指出了这种特殊情况。
您提到的代码将“非阻塞”模式配置为 VMIN=0 和 VTIME=5。这并不总是会导致 read() 像非阻塞规范读取那样立即返回;使用该代码,read() 可以等待至少半秒钟才返回。
“非阻塞”的传统定义是您的调用程序在系统调用期间不会被抢占,并且(几乎)立即获得控制权。
要获得(无条件和)立即返回(对于非规范读取),请设置 VMIN=0 和 VTIME=0(并伴有警告)。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件