我正在尝试为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与阻塞/非阻塞端口之间的关系,我将非常感激。
由于
答案 0 :(得分:5)
安德烈是对的。在非阻塞模式下,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脚本,发送器和接收器,双端口串行卡和零调制解调器电缆对此进行了测试。我证明了它的工作原理正如man page所说的那样。 VTIME是一个间歇计时器,随着每个新字节的到达而复位。
更好的设计会使计时器锚定,而不是滚动。它将继续滴答,直到它到期,或VMIN满意,以先到者为准。现有设计可以修复,但有30年的遗产需要克服。
在实践中,您可能很少遇到这种情况。但它潜伏着,所以要小心。
答案 1 :(得分:2)
确保使用fcntl 取消设置描述符的FNDELAY标志,否则忽略VMIN / VTIME。 Serial Programming Guide for POSIX Operating Systems
答案 2 :(得分:-1)
如果你使用非阻塞读取,我建议使用vmin和vtime都为0。这将为您提供如果数据可用,则将返回的行为;只要数据可用,fd就可以进行选择,轮询等。
如果你正在进行阻塞读取,那么vmin和vtime很有用。例如,如果您期望特定的数据包大小,那么您可以设置vmin。如果你想确保每半秒获得一次数据,你可以设置vtime。
显然vmin和vtime仅适用于非规范模式(非线模式)
我怀疑在非阻塞模式下,如果你将vmin设置为5,那么fd将不会被准备好读取并且读取将返回EWOULDBLOCK直到5个字符准备就绪。我不知道也没有一个简单的测试用例,因为我所做的所有连续工作都是阻塞或者都设置为0。