【问题标题】:QSerialPort with thread带线程的 QSerialPort
【发布时间】:2017-11-06 13:06:38
【问题描述】:

我一直在为一个通过 Qt 中的串行端口进行通信的项目苦苦挣扎大约两周。首先我尝试了信号/插槽方法,它错过了一些数据。然后我决定为此使用一个线程,但我得到了相同的结果。当应用程序的窗口正在调整大小或最大化/最小化时,即使在窗口栏上按住鼠标左键,它也会丢失一些数据。请帮我解决这个问题。

MainWindow 构造函数:

SerialPort *serial= new SerialPort();
serial->moveToThread(&cThread);

connect(this , &MainWindow::finished, &cThread, &QThread::quit);
connect(this , &MainWindow::destroyed, this, &SerialPort::deleteLater);
connect(serial, &SerialPort::getData, this, &MainWindow::displayData);

cThread.start();

串口读取线程:

void SerialPort::newData()
{
     mutex.lock();
     bArray.insert(bArray.length(),serial->readAll());
     mutex.unlock();

     emit getData(&bArray,&mutex);
}

串行端口构造函数:

serial = new QSerialPort();
connect(serial, &QSerialPort::readyRead, this,  &SerialPort::newData);

bArray.clear();

fill_serial_ports();
portName = find_stm32_port();

serial->setReadBufferSize(20*1024*1024); // it's a huge buffer.
bArray.reserve(20*1024*1024);  // it's a huge buffer.

open_serial_port();

另外,我认为这可能是一个错误,它会丢失一些数据并写入错误跟踪器。受让人说 QSerialPort 永远不会丢失数据,我的代码是错误的。我很困惑,我不知道在哪里犯错误。请问,你能检查我的其他解决方案吗?哪里错了?

我的错误跟踪报告(不接受):https://bugreports.qt.io/browse/QTBUG-61233

【问题讨论】:

  • 请提供一些示例代码?
  • 离题但是...如果您的单线程代码丢失了端口中的数据,那么我不禁觉得将该代码移动到另一个线程只会使 真实 问题更难调试。
  • 如果您要从串口接收大量数据,您可能必须累积从多个 readyRead 信号接收到的数据。

标签: c++ multithreading qt5


【解决方案1】:

Denis Shienkov 在 qtbugreports 中解决了这个问题。您可以查看带有线程的串行端口的 qsp-no-freeze-workaround-windows.zip 示例。

链接:https://bugreports.qt.io/browse/QTBUG-61233

【讨论】:

    【解决方案2】:

    尝试将您的内部QSerialPort 对象serial 也移动到线程cThread

    SerialPort *serial = new SerialPort();
    serial->moveToThread(&cThread);
    serial->serial.moveToThread(&cThread); // move you inner QSerialPort to cThread
    

    在上面的代码中,内部字段serial->serial.moveToTheThread(...) 发挥了作用。

    【讨论】:

    • 我会试试这个,我也认为这可能是一个错误并写信给错误跟踪器。受让人说 QSerialPort 永远不会丢失数据,我的代码是错误的。我很困惑,我不知道在哪里犯错误。请问,你能检查我的其他解决方案吗?错误在哪里?我刚刚将链接添加到我的主帖。
    • 你的代码有以下问题: 1、为什么SerialPort继承自QThread?您在 SerialPort 类中混合了 3 个职责:(a) 线程,(b) 同步,(c) 串行端口包装器。这可能会导致不可预测且非常奇怪的错误。使用聚合而不是继承。 2.从SerialPort继承convertData的原因是什么?这可能是问题的真正根源。请改用Chain of Responsibility 设计模式。 3. 将serial->moveToThread(*this) 行添加到SerialPort::SerialPort()。 4.重构你的代码,再试一次,然后回来。
    • 我刚刚尝试了示例中的终端程序,只添加了几行代码就可以启动MCU。也就是数据丢失了。如果USB_Can转换器的红色灯亮,表示有丢失的传输。但是,虽然 Hercules 是一个串口终端程序使用,但没有丢失数据。您可以在下面的视频中看到这一点。链接:drive.google.com/file/d/0B7WvtYBLRY0YVFFmRzZvWWZKVFk/view
    【解决方案3】:

    当应用程序的窗口被调整大小或最大化/最小化时,即使在窗口栏上按住鼠标左键,它也会丢失一些数据

    我编译了the code you provided to a bug tracker,用socat创建的一对虚拟串口启动它:

     socat -d -d pty,raw,echo=0 pty,raw,echo=0
    

    并模拟发送数据块,每秒增加 1 个字节:

    #!/bin/bash
    for i in {1..1000}
    do
        dd if=/dev/urandom of=/dev/pts/25 bs=1 count=$i
        sleep 1
    done
    

    您的应用程序日志如下所示:

    "bytearray length:1"
    "bytearray length:2"
    "bytearray length:3"
    "bytearray length:4"
    "bytearray length:5"
    "bytearray length:6"
    "bytearray length:7"
    ...
    

    然后我尝试调整应用程序窗口的大小、移动它、最大化/最小化、按下按钮等等。它没有任何效果:实际上,在相当长的测试会话期间,根本没有数据丢失(Ubuntu 16.04 x64)。因此,如果您仍然丢失数据,则问题可能出在您的虚拟 COM 端口上,描述为“STMicroelectronics Virtual COM Port”。

    【讨论】:

    • 感谢您的解释,但是您的测试比我的应用程序慢很多,我的应用程序的波特率为1Mbit(由于CANbus)。
    • 好的,您认为数据丢失在哪里?这是否发生在您的 convertData 线程中?
    • USBCan 设备出现无法发送数据的错误,因此错误指示灯亮。
    【解决方案4】:

    正如the comment 中已阐明的那样,问题在于

    USBCan 设备出现无法发送数据的错误,因此其错误指示灯亮。

    尝试在创建QSerialPort 实例serial 后立即添加以下行:

    serial->setFlowControl(QSerialPort::HardwareControl);
    

    如果您的设备支持 RFC232 标准,这应该启用 RTS(请求发送/CTS(清除发送)线路,并导致您的发送器在发送任何数据之前请求接收器准备就绪。有关详细信息,请参阅here

    【讨论】:

      猜你喜欢
      • 2014-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-02
      • 1970-01-01
      • 1970-01-01
      • 2015-05-12
      • 1970-01-01
      相关资源
      最近更新 更多