2012-08-17 60 views
0

我有幾個客戶端GUI窗口都來自QMainWindow。每個窗口都可能執行不同的任務,但都是從中央緩存請求數據,實現爲QThreadQt 4.7發送信號到特定的線程

所有客戶端連接到數據緩存中的相同slot,然後發出signal s提示數據緩存執行某些操作。數據緩存中的signal被排隊,因此數據緩存一次只能處理一件事情。

當數據緩存完成時,它需要通知正確的客戶端它正在做的事情已經完成。我的直接想法是發出一個signal給請求客戶關於完成。這意味着連接到一個特定的客戶端slot,然後發出一個signal它。

我必須做連接然後斷開連接到客戶端嗎?我知道QObject::sender()函數來獲取供應商。是否有某種方式僅向發送者(客戶端)發送信號?或者有沒有其他的方式來做到這一點?

+0

- 從客戶端對象或數據緩存中調用'QObject :: connect'以形成客戶端和數據緩存之間的鏈接? - 這個問題的標題是什麼意思 - 你的應用程序創建的具體線程是什麼? - 客戶端對象在接收到「數據緩存完成」信號時需要做什麼,我指的是客戶端需要從緩存中檢索多少數據? – sjwarner 2012-08-17 17:49:30

+0

澄清@sjwarner評論。我從客戶端對象調用QObject :: connect,即QMainwindow派生對象。我一直假設它們中的每一個代表一個單獨的GUI線程。返回的數據量取決於數據緩存的要求,數量可能很少或很大。我正在使用指向數據緩存的指針來訪問這些數據。正在被訪問的數據一旦被初始化就是靜態的,因此沒有鎖定機制。到目前爲止,我沒有任何衝突。 – bogflap 2012-08-22 14:14:37

回答

0

可能有更簡單的方法可以解決您的問題。例如,我會考慮研究QtConcurrent框架。或者,您也可以重新設計您的設計,以便客戶端首先連接到緩存上的「完成」信號,然後再請求緩存執行任何操作。如果沒有這些,您可能還會考慮依靠QMetaObject::invokeMethod函數(用於客戶端或緩存)。這個函數允許你使用任意的泛型參數(以線程安全的方式)在任意QObject上調用任意方法(假設你有一個指向它的指針)。

如果您使用QMetaObject::invokeMethod方法,您應該注意一些缺點。首先,您必須使用其字符串名稱調用該方法,這意味着您不會在編譯時發現是否使用了錯誤的名稱。其次,由於您的客戶端與中央緩存具有不同的線程關聯性,因此當緩存調用方法時,客戶端可能會被銷燬(可能對您而言,這對您來說不會有問題) 。最後,你可能不希望你的緩存知道它必須在它的客戶端上執行的方法的名字。

我沒有辦法繞過第一個缺點(我不確定這是否會在即將到來的Qt 5.0版本中以不同方式處理)。至於第二個和第三個問題,我建議創建封裝到一個方法的引用一個對象 - 像下面的東西:

class MethodReference 
{ 
    MethodReference(QObject* object, const QString& methodName); 

    ... 

    bool invoke(QGenericArgument val0 = QGenericArgument(), 
       QGenericArgument val1 = QGenericArgument(), 
       ... 
       QGenericArgument val9 = QGenericArgument()); 

private: 
    QPointer<QObject> mObject; 
    QString mMethod; 
}; 

你會然後把這個對象傳遞給你的緩存從客戶端。緩存然後調用此對象的調用。

請注意QPointer的使用 - 這爲您提供了一種線程安全的方法,用於在嘗試調用其上的方法之前檢查對象是否已被銷燬。由於我之前完成了這個工作,我還會告訴你,4.8之前的Qt版本有一個bug in QPointer,這會導致多線程環境中的崩潰。如果你想這樣做,請使用更新版本的Qt。

我希望這很清楚。

+0

謝謝@RA。到目前爲止,我不得不承認元對象子系統對我來說有點神祕。我儘可能少地使用它,但看到你的答案促使我再次仔細觀察它。 QMetaObject :: invokeMethod讓我想起了Java,這真的很有趣 – bogflap 2012-08-22 14:22:19