2016-11-28 90 views
2

在Qt中,是否可以从2个不同的线程同时读取和写入同一个串行端口?使用2个线程在串行端口上同时读写

+0

不,但无论如何,您认为您需要这样做很可能是错误的。当然,数据可以来自任何你想要的地方,但是'QSerialPort'方法的调用必须全部使用与'port-> thread()'相同的线程来完成。 –

+0

@Kuba Ober,我明白你的意思。但这是问题。我试图演示在一个线程上读取串行端口并在GUI线程上显示。为了测试,我需要不断写入串口,同时需要从串口读取相同的数据并显示在GUI线程中。我试图在一台机器上展示所有这些(我的笔记本电脑)。所以我想我的应用程序中有3个线程。 1个主GUI线程,1个读取器线程,1个写入器线程。 – Aham

+0

阅读器和书写器必须是相同的线程。鉴于串行端口的速度相对于CPU /内存带宽相对较低,将作业拆分为两个线程会使情况变得更糟,而不是更好:具有多个线程的开销高于保持串行端口塞入所需的工作量随时提供数据,并处理任何答复。 –

回答

1

不是。由于它的实现,不可能从不同的线程读取/写入(与Qt的任何I/O类相同)。 QSP使用允许使用“同时”从一个线程读取/写入的非阻塞(异步)I/O。

2

不是直接。您致电port的任何方法都必须在port.thread()内调用。否则是未定义的行为:您可能会格式化您的硬盘驱动器。

但您可以通过使用信号插槽机制间接地完成。而不是调用该端口的方法,让我们充当一个线程安全的接口端口的接口类:

struct PortInterface : QObject { 
    Q_SIGNAL void writeData(const QByteArray &); 
    Q_SIGNAL void hasReadData(const QByteArray &); 
    Q_OBJECT 
}; 

int main(int argc, char ** argv) { 
    QApplication app(argc, argv); 
    PortInterface interface; 
    QSerialPort port; 

    QObject::connect(&interface, &PortInterface::writeData, &port, [&](const QByteArray &data){ 
    qDebug() << "writing in thread" << QThread::currentThread(); 
    Q_ASSERT(QThread::currentThread() == port.thread()); 
    port.write(data); 
    }); 
    QObject::connect(&port, &QIODevice::readyRead, [&]{ 
    qDebug() << "reading in thread" << QThread::currentThread(); 
    Q_ASSERT(QThread::currentThread() == port.thread()); 
    emit interface.hasReadData(port.readAll()); 
    }); 

你可以调用任何线程中writeData方法:Qt的信号槽机制将包裹该电话并将其安全地交付给港口的线程。同样,可以从任何线程调用hasReadData信号。 readAll调用是从端口自己的线程完成的。处理可用数据的代码应连接到该插槽。

因此,我们可以在一个专用线程蜱一些数据写入端口定时器,我们可以监听到新的数据在主线程插槽:

QTimer sourceTimer; 
    sourceTimer.start(20); 
    QObject::connect(&sourceTimer, &QTimer::timeout, [&]{ 
    qDebug() << "timer tick in thread" << QThread::currentThread(); 
    interface.writeData(QByteArray(20, 'd')); 
    }); 
    QObject::connect(&interface, &PortInterface::hasReadData, &app, [&](const QByteArray &data){ 
    qDebug() << "data read in thread" << QThread::currentThread(); 
    qDebug() << data.toHex(); 
    }); 

    QThread sourceThread, portThread; 
    QThread::currentThread()->setObjectName("mainThread"); 
    sourceThread.setObjectName("sourceThread"); 
    portThread.setObjectName("portThread");; 
    sourceTimer.moveToThread(&sourceThread); 
    port.moveToThread(&portThread); 
    sourceThread.start(); 
    portThread.start(); 
    return app.exec(); 
} 

你可以有任何数量的对象附加到hasReadData信号。这些对象可以存在于任何线程中。回想一下,信号插槽连接是1:n种,其中0<=n。同样,你可以有任意数量的对象调用接口的writeData方法:只要他们写的数据是一个自包含的数据包,就可以保证数据包将在端口上作为单位,而不与其他数据包交织。但是,接收方必须能够描述分组,但是分组需要头部或其他同步手段(例如HDLC)。

当然,您需要先打开端口:)

+0

你能帮我安排这个代码到一个Qt项目中吗?至于上面哪段代码去哪里? – Aham

+0

@Aham想象一下散文(描述文本)不在那里。把代码片段粘在一起,你会得到一个可以编译的'main.cpp'。它不会做太多的事情,因为这个端口没有打开,但是它完成了。 –

相关问题