【问题标题】:How to change Linux interrupt timer for tcsetattr()如何更改 tcsetattr() 的 Linux 中断计时器
【发布时间】:2015-03-27 04:18:49
【问题描述】:

我正在使用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.

当使用TCSDRAIN 调用tcsetattr() 时,如果缓冲区中仍有输出数据,Linux 似乎被阻塞,并在一段时间后再次检查缓冲区以更改配置。

我对此进行了如下测试

  • 第一个正常情况

    1. 向串口写入数据
    2. 使用 tcsetattr() 更改配置
    3. 输出缓冲区中有剩余数据
    4. 进程在固定间隔内阻塞,例如 20 毫秒
    5. 醒来。
  • 第二种情况

    1. 向串口写入数据
    2. 手动执行 sleep() 5ms,这意味着有足够的时间来清除 Linux 的输出
    3. 没有剩余数据
    4. 使用 tcsetattr() 更改配置
    5. 没有阻塞

对我来说,中断时间太长了,无法做我想做的事

如何更改此中断计时器间隔? (在Ubunturaspberrypi

【问题讨论】:

    标签: c linux timer


    【解决方案1】:

    我不认为 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 函数等效于 ioctl( ) 在 Linux 中调用),我个人更喜欢让一个单独的线程除了维护这些超时之外什么都不做。这样的线程非常轻量级,不会消耗 CPU 时间,除非超时或被添加。我还可以有多个并发超时,通过一个简单的界面来检查、取消和添加超时,这使得将应用程序的其余部分设计得更加健壮和高效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多