2012-08-01 110 views
3

我有一個由生產者對象處理的一些硬件的實時數據流。 這會連接到一個消費者,它在它自己的線程中處理它,以保持gui的響應。插槽斷開後的Qt信號

mainwindow::startProcessing(){ 
    QObject::connect(producer,SIGNAL(dataReady(data*),consumer,SLOT(doData(data*))); 
    consumer->moveToThread(&consumerThread);   
    consumerThread.start(); 
} 

mainwindow::stopProcessing(){ 
    producer->disconnect(SIGNAL(dataReady(data*)); 
    consumer->cleanup();       
    delete consumer; 
} 

consumer::doData(data* x) { 
    mutex.lock(); 
    processingObject stuff 
    mutex.unlock() 
} 

consumer::cleanup() { 
    mutex.tryLock(); 
     .... blah .... 
     delete processingObject; // then doData gets called again 
} 

我的問題是,我銷燬消費者對象後 - 即使在斷開連接後,我仍然會收到張貼的信號。我嘗試了一組越來越複雜的互斥體來試圖阻止這一點,但理想的解決方案是清理等待所有未完成信號的處理。

有無論如何監測有多少未處理的信號排隊等待一個插槽?或者無論如何清除它們?

回答

3

您似乎正在從不同於它生活的線程中銷燬消費者對象.QObject通常會在銷燬時處理所有的斷開連接和事件隊列清除,如果它是在正確的線程中完成的。從Qt's documentation

調用來自除擁有該對象的一個​​(或訪問其他方式的對象)以外的線程上一個QObject刪除是不安全的,除非你能保證該對象未在該事件處理時刻。相反,使用QObject :: deleteLater()會發佈一個DeferredDelete事件,該對象的線程的事件循環將最終選取。

只要把清理在消費者的析構函數,並使用QMetaObject::invokeMethod(consumer, "deleteLater");讓消費者從自己的線程中自我毀滅。在槽上使用invokeMethod會以線程安全的方式將調用發送到deleteLater,這似乎是必要的,因爲我沒有看到說deleteLater本身是線程安全的文檔。如果您必須阻止,直到消費者被銷燬,您可以指定連接類型爲Qt::BlockingQueuedConnection,否則默認爲Qt::AutoConnection應該沒問題。

+0

Unfortunatley的處理涉及一個TCPSocket,它有一個計時器,你不能在定時器中等待的線程上使用deleteLater() – 2012-08-02 14:52:37

+0

我不太明白你的意思。消費者線程是否在QAbstractSocket :: waitFor *上被阻塞? – cgmb 2012-08-02 19:56:05

+0

我得到了一個有關deleteLater和QTimer的警告,他是否連接了socket,我認爲它必須是TCP套接字,因爲線程中沒有使用明確的定時器。 – 2012-08-02 21:07:36

1

確保你沒有連接信號多次否則考慮看看這個郵件列表歸檔可以給你一些提示/建議:

http://lists.trolltech.com/qt-interest/2000-05/thread00051-0.html

總之也許嘗試:

mainwindow::stopProcessing() 
{ 
    // Block the producer's signals. 
    producer->blockSignals(true); 

    // Perform clean up/stop 
    consumer->cleanup(); 

    // Delete the consumer, this disconnects all signals connected 
    // to the consumer. 
    delete consumer; 

    // Restore the producer's signals 
    producer->blockSignals(false); 
} 

編輯:修正了blockSignals的調用,應該是生產者不是消費者。

+0

謝謝,但似乎並沒有阻止管道中的信號。 – 2012-08-01 20:41:22

2

這裏的問題是type of connection。您使用default type of connection,因此它是Qt::AutoConnection。由於您正在連接來自不同線程的對象,因此它的工作方式爲Qt::QueuedConnection

現在我假設你的製作者更快地創建數據,然後你的消費者吃掉它們。這導致消費者線程的事件隊列中的數據緩衝。所以,當你斷開信號,你真的斷開連接,但你有一堆數據等待你在事件隊列中給你只填充,你仍然連接。

如何解決?讓消費者更快或者在消費者身上添加一些標誌,這會導致忽略消費者插槽中的數據。或者讓製片人變慢。嘗試不同的溝通模式。或使用concurrent API將作業分成多個線程。 最好的解決方案取決於細節你在做什麼。

祝你好運。