2016-11-28 88 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'。它不會做太多的事情,因爲這個端口沒有打開,但是它完成了。 –

相關問題