线程中的QSerialPort

时间:2018-08-02 14:09:51

标签: multithreading qt serial-port

这是我有史以来第一个关于stackoverflow的问题,所以请多多包涵。

我有一个虚拟串行端口USB设备,可以使用QSerialPort(Qt-5.9)与之通信。有很多数据需要发送给它(每40ms大约6 KB),并且还需要读取一些数据。设备每隔几毫秒发送一次数据。

在Mac上,我不能仅转储所有写数据,因为它似乎溢出了Mac的内部写缓冲区。如果发生这种情况,则没有任何指示,并且后续写入将永远失败。一种解决方案是在每次写入后都刷新()。 Windows和Linux可以接受大量写入数据,只要在发送或接收新批次之前有足够的时间将数据输入/输出。换句话说,在Windows和Linux上,不需要阻止通信,但是下面描述的问题仍然存在。

如果我从主线程访问端口,一切都很好。它像魅力一样运转。但是,随着flush()的写入现在被阻止。他们需要时间。我的应用程序需要能够一次与这些设备中的一个或多个通信。在这种情况下,GUI线程受苦。

因此,解决方案是将串行端口访问移至线程。这是乐趣开始的地方。我尝试过:

//////////////////////////////////////////
Device::Device  (const QString portName):
    QThread     (nullptr),
    mSerPort    (nullptr),
    mPortPath   (portName)
{
}

//////////////////////////////////////////
bool Device::StartThread (void)
{
    // Create and open serial port
    mSerPort = new QSerialPort(mPortPath);
    mSerPort->moveToThread(this);
    mSerPort->open(QIODevice::ReadWrite);
    if (mSerPort->isOpen() == false)
    {
        qDebug() << mSerPort->errorString();
    }
    // Start thread (execute run())
    start();
}

//////////////////////////////////////////
void Device::run (void)
{
    while (true)
    {
        if (mSerPort->isOpen() == true)
        {
            Read();       // Read data from the device
//          Write();      // Write data to the device
        }
        msleep(THREAD_SLEEP_MS);
    }
}

Read()和Write()只是QSerialPort的read()和write()函数的薄包装。没有与其他线程共享数据。

在这种情况下,我在端口open()上收到运行时警告:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QSerialPort(0x109676430), parent's thread is Device(0x10400b0a0), current thread is QThread(0x101503cb0)

这是可以理解的,因为从GUI线程调用了Device :: StartThread()。但是,该应用程序可以运行一会儿,读取(并在未注释Write()的情况下进行写入),但最终会因QSerialPort :: read()内部的访问冲突而崩溃。

因此,我的下一个尝试是将port open()移至run():

//////////////////////////////////////////
void Device::run (void)
{
    // Open the serial port
    mSerPort->open(QIODevice::ReadWrite);
    if (mSerPort->isOpen() == false)
    {
        qDebug() << mSerPort->errorString();
        return;
    }
    while (true)
    {
    ...

这可确保端口完全在设备线程内部。不幸的是,在这种情况下,Read()永远不会从端口获取任何数据。所有读取返回0字节。没有报告端口错误。

我在做什么错?为什么没有从设备读取数据(我是肯定的,需要读取数据)?

谢谢

1 个答案:

答案 0 :(得分:0)

听起来您没有完全将QSerialPort移到线程中以正确使用它。查阅有关如何从Qt文档中正确创建线程的指南:https://wiki.qt.io/QThreads_general_usage

要了解的重要部分是,许多旧指南告诉您在run中覆盖QThread方法-请勿这样做!我无法从您发布的代码中得知您是否继承自QThread

如果确实有用于串行通信的单独线程,则还应该能够使用QTimer来定期发送必须发送到设备的消息,从而进入事件驱动的系统。