我正在使用serial port
,与此通信时,我必须使用tcsetattr()
和TCSDRAIN
模式更改配置。
TCSADRAIN
The change should take place after all output written to fd has been read by the master pseudoterminal. Use this value when changing terminal attributes that affect output.
在用
tcsetattr()
调用TCSDRAIN
时,如果缓冲区中仍然有输出数据,Linux似乎被阻塞,并在经过一些中断时间后再次检查缓冲区以更改配置。我如下测试
第一师范案
将数据写入串行
使用tcsetattr()更改配置
输出缓冲区中有剩余数据
该过程在有规律的时间间隔(例如20毫秒)内被阻止
醒来。
第二种情况
将数据写入串行
手动使用sleep()持续5毫秒,这意味着要留出足够的时间清除对Linux的输出
没有剩余数据
使用tcsetattr()更改配置
没有障碍
对我来说,打扰时间太长,无法做我想做的事
如何更改此中断计时器间隔?
(在
Ubuntu
和raspberrypi
中) 最佳答案
我不认为termios结构的.cc[VTIME]
字段会影响刷新超时,如果那正是您要的。据我所知,它仅影响read()
行为。
但是,有几种方法可以控制在放弃之前内核尝试耗尽/刷新的时间间隔。
一种选择是使用fcntl(fd, F_SETFL, O_NONBLOCK)
(临时)将描述符设置为非阻塞状态,并使用clock_gettime(CLOCK_MONOTONIC, &now)
和nanosleep()
在适当的时间间隔内重试tcsetattr(fd, TCSADRAIN, &attrs)
几次,直到成功为止。然后使用fcntl(fd, F_SETFL, 0)
将描述符恢复为正常模式。如果tcsetattr()
调用因errno == EWOULDBLOCK || errno == EAGAIN
失败,请使用tcsetattr(fd, TCSANOW, &attrs)
丢弃所有未读/未发送的数据。
请注意,我尚未在RPi上测试以上内容!它可能不适用于某些特定的体系结构/串行端口驱动程序,因为可以将刷新/漏极间隔硬编码到驱动程序中,而忽略描述符处于非阻塞模式的事实。但是,那将是一个错误,并且可以通过内核补丁修复。 (换句话说,这应该可行,但是某些串行端口驱动程序可能很糟糕,并且忽略了上面的非阻塞性,并且将阻塞直到未指定的间隔。)
另一种选择是使用计时器来发出信号。如果安装了不带SA_RESTART
标志的用于处理该信号的函数,则信号的传递将中断阻塞的tcdrain()
/ tcflush()
/ tcsetattr()
调用。 (如果该进程使用多个线程,则应在所有其他线程中阻止该信号,否则内核将只选择该进程的一个线程来传递信号。如果不是阻塞调用中的线程,则该阻塞调用不会被打断。)
因为信号是中断大多数系统调用和库函数的一种非常可靠的方法(请参见man 7 signal中的信号处理程序中断系统调用和库函数的部分-termios函数等效于Linux中的ioctl()调用),所以我个人更喜欢有一个单独的线程除了维持这些超时什么都不做。这样的线程非常轻巧,除非经过超时或添加了超时,否则不会占用CPU时间。我还可以有多个并发超时,并具有一个简单的界面来检查,取消和添加超时,这使将应用程序的其余部分设计得更健壮和更高效变得更加容易。
关于c - 如何为tcsetattr()更改Linux中断计时器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29293227/