Qt串口的C ++线程模式

时间:2014-09-05 05:30:22

标签: c++ multithreading qt

我的目标是在不阻塞主线程(GUI)的情况下从串行设备接收消息,并尝试将平台相关逻辑(GUI和串行端口)与业务逻辑(处理消息)分开以便于移植到其他平台

上下文:我正在使用Qt和QtSerialPort模块。消息协议很简单,0xff用于结束每条消息。

到目前为止,我找到了4个解决方案:

方法1:

  1. 使用一个线程读取串口并填充缓冲区

  2. 使用另一个线程来读取缓冲区,提取有效的消息(进入另一个缓冲区?不知道这将如何工作)

  3. 使用另一个线程来解析消息

  4. 方法2:

    1. 使用一个线程读取串口,并将有效消息提取到缓冲区

    2. 使用另一个线程来解析消息

    3. 方法3:

      1. 使用一个线程读取串口,提取有效消息,并阻止该消息处理,利用QtSerialPort的内部读缓冲来缓冲传入数据
      2. 方法4:

        1. 使用主线程异步读取串口,提取有效消息,并为每条消息生成一个新线程来处理它们
        2. 方法1,2和3的不同之处在于一般工作负载被分成的线程数,但我不知道哪个最好。

          我目前正在使用方法4,由于产生了大量的线程,每次我移动或与GUI交互,串行通信都非常低效且在低端计算机上无法正常工作暂停。为每条消息生成一个线程也会使消息的顺序不确定,这到目前为止还不是一个主要问题......

          是否有其他方法,每种方法的优点(如果有的话)和缺点是什么,哪种方法最好?谢谢!

          编辑:在主线程中处理消息的一个问题是与GUI交互(甚至移动窗口)会阻塞消息处理功能。有没有办法解决这个问题?

3 个答案:

答案 0 :(得分:4)

我认为使用多线程可以获得两个主要优势:

  1. 由于串口处理例程阻止了GUI处理例程,避免了较差的GUI性能
  2. (也许更重要)当GUI例程拖延串行数据读取程序太久时,避免因缓冲区溢出而导致串行数据丢失。
  3. 您应该只需要生成一个线程。只需让该线程从串口读取数据(通过将QSerialPort的readyRead()信号连接到调用QSerialPort对象上的read()的插槽),然后每当它发出一个信号(带有QByteArray参数)想要将一些串行数据发送到GUI。您的主/ GUI线程可以通过QueuedConnection接收数据,该QueuedConnection不会阻塞串行线程或主/ GUI线程。

    这就是它的全部内容;唯一需要担心的是干净关机。确保在QThread的quit()插槽中有另一个跨线程信号/插槽连接,这样当它退出时,你可以发出该信号然后在QThread上调用wait()以等待它响应远。一旦wait()返回,您可以安全地删除QThread对象。

答案 1 :(得分:2)

您可以通过简单地依赖Qt事件循环来避免额外的线程(到目前为止主线程,也是处理GUI清除的线程,只有在串口实际接收到消息时才会被阻止)。

否则,如果你想在专用线程中完全处理串口,那么解决方案就是实现一个派生自QThread的类,然后用这样的东西覆盖run()函数:

void MyClass::run()
{
     QSerialPort port;

     // ... serial port initialization here

     // Connect signals/slots
     connect(&port, SIGNAL(readyRead()), this, SLOT(readData()));

     port.open();

     // Start a new message loop on this thread
     exec();
}

其中readDataMyClass中用于处理接收数据的函数。由于port由新线程拥有(在run()中创建),因此其事件将由线程本身处理(以与主线程完全独​​立的方式)。

如果您希望在某些时候与主线程进行通信(例如:您在串行上收到某些内容会导致GUI更改),那么您仍然可以使用Qt的信号/插槽。只需在MyClass上实现一个信号,并在主线程处理的对象上实现一个插槽(例如:您的主表单):然后只需连接MyClass的信号和主表单上的插槽即可。 #39; re done:signal / slots是 解决方案,用于Qt中的跨线程通信。

答案 2 :(得分:0)

您还可以避免使用任何(其他)线程并利用Qt event loop。阅读eventsQioDevice;那么Qt会将你的设备文件描述符传递给它的多路复用循环(例如poll(2) ....);可能QSocketNotifier应该在非套接字文件描述符(如串行设备)上工作(在Posix上)。

详细信息可能是特定于操作系统的