【问题标题】:Reading from the serial port in a multi-threaded program on Linux在 Linux 上的多线程程序中从串口读取
【发布时间】:2011-03-14 15:00:19
【问题描述】:

我正在 linux 中编写一个程序,通过串行接口与一个硬件连接。该设备以大约 10Hz 的频率发送大约 30-40 字节的数据包。该软件模块将与其他模块交互并通过 IPC 进行通信,因此它必须执行特定的 IPC 睡眠,以允许它在没有做任何有用的事情时接收它订阅的消息。

目前我的代码如下所示:

while(1){
  IPC_sleep(some_time);
  read_serial();
  process_serial_data();
}

这样做的问题是,有时会在串行端口上只有一小部分下一个数据包可用时执行读取,这意味着直到下一次循环时才会全部读取。对于特定的应用程序,最好在数据可用时立即读取数据,并且程序在读取时不会阻塞。

这个问题的最佳解决方案是什么?

【问题讨论】:

  • 如果您提供更多关于 IPC_sleep 中发生的事情的详细信息,可能会更容易回答

标签: c linux multithreading serial-port


【解决方案1】:

将到目前为止您收到的消息存储在某种缓冲区中。

如果您不想在等待新数据时阻塞,请使用select() on the serial port 之类的内容来检查是否有更多数据可用。如果没有,您可以继续做一些处理或任何需要做的事情,而不是阻塞,直到有数据要获取。

当其余数据到达时,添加到缓冲区并检查是否有足够的数据来组成完整的消息。如果有,则对其进行处理并将其从缓冲区中删除。

【讨论】:

    【解决方案2】:

    最好的办法就是不睡觉!我的意思是一个好的解决方案可能是混合 IPC 事件和串行事件。 select 是一个很好的工具。然后你必须找到和选择兼容的IPC机制。

    • 基于socket的IPC是select()able
    • 基于管道的 IPC 是 select()able
    • posix 消息队列也可选择

    然后你的循环看起来像这样

    while(1) {
        select(serial_fd | ipc_fd); //of course this is pseudo code
        if(FD_ISSET(fd_set, serial_fd)) {
            parse_serial(serial_fd, serial_context);
            if(complete_serial_message)
                process_serial_data(serial_context)
        }
        if(FD_ISSET(ipc_fd)) {
            do_ipc();
        }
    }
    

    read_serial 被替换为parse_serial,因为如果您将所有时间都花在等待完整的串行数据包上,那么选择的所有好处都将丢失。但是从您的问题来看,您似乎已经在这样做了,因为您提到在两个不同的循环中获取串行数据。
    使用建议的架构,您在 IPC 和串行端都有良好的反应性。您可以在串行数据可用时立即读取它们,但无需停止处理 IPC。

    当然,它假设您可以更改 IPC 机制。如果不能,也许您可​​以创建一个“桥接进程”,一方面与您所使用的任何 IPC 接口,另一方面使用select()able IPC 与您的串行代码进行通信。

    【讨论】:

      【解决方案3】:

      您必须缓存足够多的消息才能知道它是否是完整的消息,或者您是否会有完整的有效消息。

      如果它无效或不在可接受的时间范围内,那么你就扔掉它。否则,您保留并处理它。

      这通常称为实现设备协议的解析器。

      【讨论】:

      • @Amigable Clark Kant:不,你误解了圣哈辛托的评论。为了重新同步状态,需要丢弃数据。想想如果设备在发送数据包的过程中重置会发生什么。或者更糟糕的是,它被锁定了。也许主人正在等待一段时间的答复,它有办法重置设备以使其恢复工作状态。
      • 谢谢,弗洛林。这确实是我的意思,也是 OP 所要求的。
      【解决方案4】:

      这是需要的算法(阻塞):

      while(! complete_packet(p) &&  time_taken < timeout)
      {
         p += reading_device.read(); //only blocks for t << 1sec. 
      
         time_taken.update();   
      }
      //now you have a complete packet or a timeout. 
      

      您可以根据需要散布回调,或在处理循环中注入相关部分。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多