在Qt中,是否可以同时从2个不同的线程读取和写入相同的串口?
答案 0 :(得分: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)。
当然你需要先打开端口:)
答案 1 :(得分:1)
不。由于其实现,不可能从不同的线程进行读/写(与Qt的任何I / O类相同)。 QSP使用非阻塞(异步)I / O,允许从一个线程使用读/写&#34;同时&#34;。