【问题标题】:termios VMIN VTIME and blocking/non-blocking read operationstermios VMIN VTIME 和阻塞/非阻塞读操作
【发布时间】:2013-11-22 20:45:54
【问题描述】:

我正在尝试为 Linux 编写一个简单的 C 串行通信程序。我对阻塞/非阻塞读取和 VMIN/VTIME 关系感到困惑。

我的问题是,是否应该根据我是否有阻塞/非阻塞打开调用来设置 VMIN/VTIME?

例如,如果我有以下公开通话:

open( "/dev/ttyS0", O_RDWR|O_NONBLOCK|O_NOCTTY)

我应该将 VMIN/VTIME 设置为:

.c_cc[VTIME]    = 0;    
.c_cc[VMIN]     = 0;

如果我有这样的阻塞模式:

open( "/dev/ttyS0", O_RDWR|O_NOCTTY)

我应该将 VMIN/VTIME 设置为:

.c_cc[VTIME]    = 0;    
.c_cc[VMIN]     = 1;

?

即使端口打开标志设置得当,设置 VMIN/VTIME 有什么区别吗?

如果有人能帮助我理解 VMIN/VTIME 和阻塞/非阻塞端口之间的关系,我将不胜感激。

谢谢

【问题讨论】:

    标签: linux serial-port


    【解决方案1】:

    安德烈是对的。在非阻塞模式下,VMIN/VTIME 无效(FNDELAY / O_NDELAY 似乎是 O_NONBLOCK 的 linux 变体,可移植的 POSIX 标志)。

    在非阻塞模式下对文件使用 select() 时,每个到达的字节都会收到一个事件。在高串行数据速率下,这会影响 CPU。最好对 VMIN 使用阻塞模式,这样 select() 会在触发事件之前等待一个数据块,而 VTIME 来限制延迟,对于小于 VMIN 的块。

    Sam 说“如果你想确保每半秒获取一次数据,你可以设置 vtime”(VTIME = 5)。

    直觉上,您可能认为这是真的,但事实并非如此。 BSD termios 手册页比 linux 解释得更好(尽管它们的工作方式相同)。 VTIME 定时器是一个interbyte 定时器。它从每个到达串行端口的新字节开始。在最坏的情况下,select() 在触发事件之前最多可以等待 20 秒。

    假设您有 VMIN = 250、VTIME = 1 和 115200 bps 的串行端口。还假设您有一个连接的设备以​​ 9 cps 的一致速率缓慢发送单个字节。字节之间的时间为 0.11 秒,足以让 0.10 的字节间计时器到期,并且 select() 为每个字节报告一个可读事件。一切都很好。

    现在假设您的设备将其输出速率提高到 11 cps。字节之间的时间为 0.09 秒。字节间计时器到期的时间还不够长,并且对于每个新字节,它都会重新开始。要获得可读事件,必须满足 VMIN = 250。在 11 cps 时,需要 22.7 秒。看起来您的设备已停止运行,但 VTIME 设计是延迟的真正原因。

    我用两个 Perl 脚本、发送器和接收器、一个双端口串行卡和一根空调制解调器电缆对此进行了测试。我证明它像手册页所说的那样工作。 VTIME 是一个字节间计时器,随着每个新字节的到来而重置。

    更好的设计是将计时器固定,而不是滚动。它将继续滴答作响,直到到期或满足 VMIN,以先到者为准。现有设计可以修复,但要克服 30 年的遗留问题。

    在实践中,您可能很少遇到这种情况。但它潜伏着,所以要小心。

    【讨论】:

    • cmrr.umn.edu/~strupp/serial.html#config 文章中,它说“在规范输入模式下或通过 open 或 fcntl 在文件上设置 NDELAY 选项时忽略超时”,然后它说“VTIME 指定等待传入字符的时间量,以十分之一秒为单位。如果 VTIME 设置为 0(默认值),则读取将无限期地阻塞(等待),除非在带有 open 或 fcntl 的端口上设置了 NDELAY 选项。这似乎意味着当 VTIME 为 0 时,您应该使用 O_NDELAY,但是当 VTIME > 0 时,您不应该使用 O_NDELAY。对吗?
    【解决方案2】:

    确保取消设置使用 fcntl 的描述符的 FNDELAY 标志,否则 VMIN/VTIME 将被忽略。 Serial Programming Guide for POSIX Operating Systems

    【讨论】:

      【解决方案3】:

      如果您使用非阻塞读取,我建议您同时使用 vmin 和 vtime 0。这会给你一个行为,如果数据可用,那么它将被返回;当数据可用时,fd 将准备好进行选择、轮询等。

      vmin 和 vtime 在您进行阻塞读取时很有用。例如,如果您期望特定的数据包大小,那么您可以设置 vmin。如果您想确保每半秒获取一次数据,您可以设置 vtime。

      显然 vmin 和 vtime 只适用于非规范模式(non-line mode)

      我的怀疑是,在非阻塞模式下,如果您将 vmin say 设置为 5,则 fd 不会准备好读取,并且 read 将返回 EWOULDBLOCK,直到准备好 5 个字符。我不知道也没有简单的测试用例可以尝试,因为我所做的所有串行工作要么被阻塞,要么都设置为 0。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-07-06
        • 2021-10-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多