2012-12-19 32 views
11

執行方法時,我有以下的代碼使用QMetaObject :: invokeMethod中:爲什麼從線程

class A : public QObject 
{ 
    Q_OBJECT 
public: 
    A() : QObject() 
    { 
     moveToThread(&t); 
     t.start(); 
    } 
    ~A() 
    { 
     t.quit(); 
     t.wait(); 
    } 

    void doSomething() 
    { 
     QMetaObject::invokeMethod(this,"doSomethingSlot"); 
    } 
public slots: 
    void doSomethingSlot() 
    { 
     //do something 
     emit ready(); 
    } 
signals: 
    void ready(); 
private: 
    QThread t; 
} 

doSomething爲什麼它必須通過QMetaObject::invokeMethod被調用的問題。我知道有一些連接類型。 有人可以解釋一下底下是什麼?

+1

ecatmur給你完美的答案。你有另一個問題,讓線程作爲移動到該線程的對象的成員是非常糟糕的主意,在銷燬期間(使用deleteLater時),你可能會遇到奇怪的問題。 –

+0

有關完整的說明,請閱讀[本文檔](http://doc.qt.digia.com/4.2/threads.html#per-thread-event-loop) –

+0

@MarekR:有什麼問題?我已經從http://stackoverflow.com/questions/13878745/correct-way-of-threading-in-qt – krzych

回答

23

如你沒有指定Qt::ConnectionType,該方法將被調用作爲Qt::AutoConnection,這意味着它將被同步調用(像普通的函數調用)如果對象的線程關聯性是到當前線程,和異步除此以外。 「異步」意味着QEvent被構造並推送到消息隊列中,並在事件循環到達時處理。

使用QMetaObject::invokeMethod如果收件人對象可能是在另一個線程的原因是試圖直接在另一個線程的對象上調用插槽可導致腐敗或更糟,如果它訪問或修改非線程安全的數據。

+0

你的意思是說,如果我從另一個線程使用A.doSomething()它可能會導致腐敗?爲什麼這樣?你能否描述這個機制呢? – krzych

+1

@krzych例如,如果您從QString同時讀取另一個線程正在修改它,那麼它可能看起來處於不一致的狀態,從而導致無效指針的間接尋址。 – ecatmur

18

我喜歡這一招:

void A:doSomethingSlot() 
{ 
    if (thread()!=QThread::currentThread()) { 
     QMetaObject::invokeMethod(this,"doSomethingSlot", Qt::QueuedConnection); 
     return; 
    } 
    // this is done always in same thread 
    ... 
    emit ready(); 
}