我有this code用于在Linux中从串行端口阅读,但我不知道在读取串行端口时阻塞和非阻塞有什么区别,在哪种情况下哪种更好?
g52tjvyc1#
您提到的代码编写和注解都很糟糕。该代码不符合Setting Terminal Modes Properly和Serial Programming Guide for POSIX Operating Systems中描述的POSIX可移植性实践。该代码没有提到它使用非规范(又名原始)模式,并重复使用“阻塞”和“非阻塞”术语来描述VMIN和VTIME属性。(The该代码的作者报告说,它早于POSIX标准,因此不符合POSIX标准。这是可以理解的,但随后发布并倡导使用可能不可移植的旧代码(即在替代情况下按预期运行)是值得怀疑的。)“阻塞”与“非阻塞”读取的传统定义是基于读取调用“何时”返回到程序(并使用下一条语句继续执行)以及程序的读取缓冲区中是否会存储数据。阻塞读取是默认模式,除非通过打开带有O_NONBLOCK或O_NDELAY标志的串行终端请求非阻塞读取。
规范模式
对于串行终端的阻塞规范读调用,一行文本(又名记录)将总是返回到提供的缓冲区(除非发生错误)。读调用将阻塞(即挂起程序的执行),只要它需要接收和处理行终止字符。串行终端的非阻塞规范读调用总是“立即”返回。读可能返回也可能不返回任何数据。如果(自上次读调用以来)至少有一行文本被接收并存储在系统缓冲区中,则最老的行将从系统缓冲区中删除并复制到程序缓冲区中。返回码将指示数据长度。如果(自上一个读取调用以来)尚未接收和处理行终止字符,则没有(完整)行文本可用。为()将返回EAGAIN错误(即返回代码和errno设置为EAGAIN)。然后程序可以执行某些计算,或从另一个设备请求I/O,或delay/sleep。在任意延迟之后,或者通过poll()或select()发出通知,您的程序都可以重试read()。这个答案中包含了一个使用阻塞规范模式进行读取的示例程序。
非规范模式
当串行终端配置为非规范模式时,termiosc_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应由程序调整,以适应预期的典型消息或数据报长度和/或每次read()检索和处理的数据的最小大小。VTIME应由程序调整,以适应预期串行数据的典型突发或到达速率和/或等待数据或基准的最长时间。VMIN和VTIME值相互作用以确定读取应该何时返回的标准;它们的确切含义取决于它们中的哪一个是非零的。2有四种可能的情况。
This web page将其解释为:
这是一个完全非阻塞的读取-调用直接从驱动程序的输入队列中立即得到满足。如果数据可用,它将被传输到调用者的缓冲区,最多n字节,然后返回。否则,立即返回0,表示“没有数据”。我们将注意到,这是串行端口的“轮询”,几乎总是一个坏主意。如果重复执行,它会消耗大量的处理器时间,而且效率很低。除非你真的知道你在做什么,否则不要使用这种模式。
这是一个纯粹的定时读取。如果输入队列中有数据,它将被传输到调用者的缓冲区,最多n字节,并立即返回给调用者。否则,驱动程序将阻塞,直到数据到达,或从调用开始到VTIME十分之一过期。如果定时器过期而没有数据,则返回零。单个字节足以满足此读取调用。但是如果输入队列中有更多的可用时间,它将返回给调用者。注意这是一个总计时器,而不是字符间计时器。
A读当VMIN字符已传输到调用程序的缓冲区,或VTIME十分之一的字符间隔到期时,满足()。由于此定时器在第一个字符到达之前不会启动,因此如果串行线路空闲,此调用可能会无限期阻塞。这是最常见的操作模式,我们将VTIME视为字符间超时,而不是一个整体。这个调用不应该返回零字节读取。
这是一个计数读取,只有当至少VMIN字符被传输到调用者的缓冲区时才能满足--不涉及计时组件。这个读取可以从驱动程序的输入队列(调用可以立即返回)中满足,或者通过等待新数据到达:在这方面,调用可能会无限期地阻塞。我们认为,如果nbytes小于VMIN,则这是未定义的行为。注意当VMIN=1时,VTIME规范将是无关紧要的。任何数据的可用性将总是满足单字节的最小标准,因此时间标准可以忽略(因为它将是一个具有非零VMIN的字符间时间规范)。您提到的代码将“非阻塞”模式配置为VMIN=0和VTIME=5。这不会像非阻塞规范读取那样使read()立即返回;对于该代码,read()在返回之前应始终等待至少半秒。“非阻塞”的传统定义是调用程序在系统调用期间不被抢占,并且(几乎)立即恢复控制。要获得(无条件和)立即返回(对于非规范读取),请设置VMIN=0和VTIME=0(附带警告)。
1条答案
按热度按时间g52tjvyc1#
您提到的代码编写和注解都很糟糕。该代码不符合Setting Terminal Modes Properly和Serial Programming Guide for POSIX Operating Systems中描述的POSIX可移植性实践。该代码没有提到它使用非规范(又名原始)模式,并重复使用“阻塞”和“非阻塞”术语来描述VMIN和VTIME属性。
(The该代码的作者报告说,它早于POSIX标准,因此不符合POSIX标准。这是可以理解的,但随后发布并倡导使用可能不可移植的旧代码(即在替代情况下按预期运行)是值得怀疑的。)
“阻塞”与“非阻塞”读取的传统定义是基于读取调用“何时”返回到程序(并使用下一条语句继续执行)以及程序的读取缓冲区中是否会存储数据。阻塞读取是默认模式,除非通过打开带有O_NONBLOCK或O_NDELAY标志的串行终端请求非阻塞读取。
规范模式
对于串行终端的阻塞规范读调用,一行文本(又名记录)将总是返回到提供的缓冲区(除非发生错误)。读调用将阻塞(即挂起程序的执行),只要它需要接收和处理行终止字符。
串行终端的非阻塞规范读调用总是“立即”返回。读可能返回也可能不返回任何数据。
如果(自上次读调用以来)至少有一行文本被接收并存储在系统缓冲区中,则最老的行将从系统缓冲区中删除并复制到程序缓冲区中。返回码将指示数据长度。
如果(自上一个读取调用以来)尚未接收和处理行终止字符,则没有(完整)行文本可用。为()将返回EAGAIN错误(即返回代码和errno设置为EAGAIN)。然后程序可以执行某些计算,或从另一个设备请求I/O,或delay/sleep。在任意延迟之后,或者通过poll()或select()发出通知,您的程序都可以重试read()。
这个答案中包含了一个使用阻塞规范模式进行读取的示例程序。
非规范模式
当串行终端配置为非规范模式时,termiosc_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应由程序调整,以适应预期的典型消息或数据报长度和/或每次read()检索和处理的数据的最小大小。
VTIME应由程序调整,以适应预期串行数据的典型突发或到达速率和/或等待数据或基准的最长时间。
VMIN和VTIME值相互作用以确定读取应该何时返回的标准;它们的确切含义取决于它们中的哪一个是非零的。2有四种可能的情况。
This web page将其解释为:
这是一个完全非阻塞的读取-调用直接从驱动程序的输入队列中立即得到满足。如果数据可用,它将被传输到调用者的缓冲区,最多n字节,然后返回。否则,立即返回0,表示“没有数据”。我们将注意到,这是串行端口的“轮询”,几乎总是一个坏主意。如果重复执行,它会消耗大量的处理器时间,而且效率很低。除非你真的知道你在做什么,否则不要使用这种模式。
这是一个纯粹的定时读取。如果输入队列中有数据,它将被传输到调用者的缓冲区,最多n字节,并立即返回给调用者。否则,驱动程序将阻塞,直到数据到达,或从调用开始到VTIME十分之一过期。如果定时器过期而没有数据,则返回零。单个字节足以满足此读取调用。但是如果输入队列中有更多的可用时间,它将返回给调用者。注意这是一个总计时器,而不是字符间计时器。
A读当VMIN字符已传输到调用程序的缓冲区,或VTIME十分之一的字符间隔到期时,满足()。由于此定时器在第一个字符到达之前不会启动,因此如果串行线路空闲,此调用可能会无限期阻塞。这是最常见的操作模式,我们将VTIME视为字符间超时,而不是一个整体。这个调用不应该返回零字节读取。
这是一个计数读取,只有当至少VMIN字符被传输到调用者的缓冲区时才能满足--不涉及计时组件。这个读取可以从驱动程序的输入队列(调用可以立即返回)中满足,或者通过等待新数据到达:在这方面,调用可能会无限期地阻塞。我们认为,如果nbytes小于VMIN,则这是未定义的行为。
注意当VMIN=1时,VTIME规范将是无关紧要的。任何数据的可用性将总是满足单字节的最小标准,因此时间标准可以忽略(因为它将是一个具有非零VMIN的字符间时间规范)。
您提到的代码将“非阻塞”模式配置为VMIN=0和VTIME=5。这不会像非阻塞规范读取那样使read()立即返回;对于该代码,read()在返回之前应始终等待至少半秒。
“非阻塞”的传统定义是调用程序在系统调用期间不被抢占,并且(几乎)立即恢复控制。
要获得(无条件和)立即返回(对于非规范读取),请设置VMIN=0和VTIME=0(附带警告)。