Linux 阻塞与非阻塞串行读取

2024-09-30 15:23:00
admin
原创
140
摘要:问题描述:我有这个用于在 Linux 中从串行读取的代码,但我不知道在读取串行端口时阻塞和非阻塞之间有什么区别,以及在哪种情况下哪一个更好?解决方案 1:在我看来,您提到的代码编码和注释都很糟糕。该代码不符合 POSIX 可移植性实践,如正确设置终端模式和POSIX 操作系统串行编程指南中所述。该代码没有提到...

问题描述:

我有这个用于在 Linux 中从串行读取的代码,但我不知道在读取串行端口时阻塞和非阻塞之间有什么区别,以及在哪种情况下哪一个更好?


解决方案 1:

在我看来,您提到的代码编码和注释都很糟糕。该代码不符合 POSIX 可移植性实践,如正确设置终端模式POSIX 操作系统串行编程指南中所述。该代码没有提到它使用非规范(又称原始)模式,并重用“阻塞”和“非阻塞”术语来描述VMINVTIME属性。

(该代码的作者报告说它早于 POSIX 标准,因此不符合要求。这是可以理解的,但随后发布并提倡使用可能不可移植的旧代码(即在其他情况下无法按预期运行)是值得怀疑的。)


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

规范模式

对于串行终端的阻塞规范读取调用,一行(又称记录)文本将始终返回到提供的缓冲区中(除非发生错误)。读取调用将阻塞(即暂停执行程序),直到收到并处理行终止符为止。

串行终端的非阻塞标准读取调用将始终“立即”返回。读取可能会或可能不会返回任何数据。

如果(自上次读取调用以来)至少已收到一行文本并将其存储在系统缓冲区中,则将从系统缓冲区中删除最旧的行并将其复制到程序的缓冲区中。返回代码将指示数据长度。如果

(自上次读取调用以来)尚未收到和处理行终止符,则没有可用的(完整)文本行。read ()将返回 EAGAIN 错误(即 -1 返回代码和errno设置为 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以适应预期的典型消息或数据报长度和/或每次读取 ()检索和处理的数据的最小大小。程序应调整

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(并伴有警告)。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   681  
  在项目管理领域,集成产品开发(IPD)流程以其高效、协同的特点,被众多企业视为提升产品竞争力的关键。IPD流程强调跨部门、跨职能的紧密合作,以确保产品从概念到市场各个环节的无缝衔接。然而,实现这一目标并非易事,它需要企业深刻理解并掌握IPD流程中的跨部门协作艺术。本文将深入探讨IPD流程中跨部门协作的三个关键点,旨在为...
IPD项目管理咨询   9  
  掌握IPD流程图:提升团队协作的关键路径在当今快速变化的商业环境中,团队协作的效率与效果直接关系到项目的成功与否。集成产品开发(Integrated Product Development,简称IPD)作为一种先进的研发管理理念,通过跨部门、跨领域的协同工作,能够显著提升产品开发的速度与质量。而IPD流程图,则是这一理...
IPD流程阶段   9  
  IPD流程概述:理解其核心价值与实施背景集成产品开发(Integrated Product Development,简称IPD)是一种先进的产品开发管理理念,它强调跨部门协作、市场导向和快速响应变化的能力。IPD流程不仅关注产品本身的技术创新,更注重将市场、研发、生产、销售等各个环节紧密集成,以实现产品从概念到市场的高...
华为IPD是什么   7  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程以其跨部门协作、高效决策和快速响应市场变化的特点,被众多企业视为提升竞争力的关键。然而,实践IPD流程并非易事,项目管理中的种种错误往往阻碍了其效果的充分发挥。本文旨在深入探讨如何在实施IPD流程时避免这些常见错误,...
IPD框架   7  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用