不直接。您在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)。
当然你需要先打开端口:)