web-dev-qa-db-ja.com

スレッドからメソッドを実行するときに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経由で呼び出さなければならないのかという質問。接続タイプに何かがあることは知っています。 誰かがボンネットの下にあるものを説明できますか?

12
krzych

Qt::ConnectionTypeを指定していないため、メソッドはQt::AutoConnectionとして呼び出されます。つまり、オブジェクトのスレッドアフィニティが現在のスレッドに対するものである場合、メソッドは同期的に呼び出されます(通常の関数呼び出しのように)。 、それ以外の場合は非同期。 「非同期」とは、QEventが作成されてメッセージキューにプッシュされ、イベントループがそれに到達したときに処理されることを意味します。

受信者オブジェクトが別のスレッドにある可能性がある場合にQMetaObject::invokeMethodを使用する理由は、別のスレッドのオブジェクトでスロットを直接呼び出そうとすると、スレッドセーフでないデータにアクセスまたは変更した場合に破損または悪化する可能性があるためです。

23
ecatmur

私はこのトリックが好きです:

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