2009-08-01 19 views
5

私のアプリケーションには、メインスレッドとワーカースレッド(QThread)があります。
メインスレッドから、私のワーカースレッドのメソッドを呼び出して、スレッドのコンテキストで実行させたいと思います。QThreadのコンテキストでメソッドを呼び出す

私はQMetaObject::invokeMethodを試してみましたが、QueuedConnectionオプションを付けましたが、機能しません。
私はまた、(ワーカースレッドのスロットに接続されている)メインスレッドから信号を発信しようとしましたが、それも失敗しました。ここで

は、私が試したおおよそ何の抜粋です:

class Worker : public QThread 
{ 
    Q_OBJECT 

public: 
    Worker() { } 

    void run() 
    { 
     qDebug() << "new thread id " << QThread::currentThreadId(); 
     exec(); 
    } 

public slots: 
    void doWork() 
    { 
     qDebug() << "executing thread id - " << QThread::currentThreadId(); 
    } 
}; 

QMetaObjectの方法の使用:シグナルの方法を使用して

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    qDebug() << "main thread id - " << QThread::currentThreadId(); 

    Worker worker; 
    worker.start(); 

    QMetaObject::invokeMethod(&worker, "doWork", Qt::QueuedConnection); 

    return a.exec(); 
} 

を:

class Dummy : public QObject 
{ 
    Q_OBJECT 

public: 
    Dummy() { } 

public slots: 
    void askWork() { emit work(); } 

signals: 
    void work(); 
}; 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    qDebug() << "main thread id - " << QThread::currentThreadId(); 

    Worker worker; 
    worker.start(); 

    Dummy dummy; 
    QObject::connect(&dummy, SIGNAL(work()), &worker, SLOT(doWork()), Qt::QueuedConnection); 

    QTimer::singleShot(1000, &dummy, SLOT(askWork())); 

    return a.exec(); 
} 

どちらの方法がメインになりますスレッドIDはQThreaddoWorkに印刷されています。

また、私は単純なプロデューサー - コンシューマーを実装することを考えましたが、これが機能すれば、このようにしない理由がありますか?

答えて

3

問題は、レシーバ(QThread)がメインスレッド内に存在するため、メインスレッドのイベントループがスロットを実行することにあります。 Qtのドキュメントから

:スレッドのイベントループに戻るは、オブジェクトが属する場合

キューに入れられた接続では、スロットが呼び出されます。スロットは、レシーバオブジェクトが存在するスレッドで実行されます。

これまで私が見つけた解決策は、スレッドのrun()内にオブジェクトを作成して代わりにスロットを使用することでした。そうすることで、受信者の所有者はスレッドであり、スロットはスレッドコンテキストで呼び出されます。

0

関数を呼び出したり、シグナルを送信したりする前に、ワーカースレッドが完了したようです。

+1

exec()の呼び出しのためにワーカースレッドがイベントループ内にあります。 –

2

単純なプロデューサ - コンシューマの例については、Bradley T. Hughes Treading without the headacheのブログエントリを参照してください。

2

この例では、Workerクラスを分割して、目的どおりに動作させる方法を示します。また、スロットに接続できるように、Workerインスタンスへの参照またはポインタを使用可能にする必要があります。

class Worker : public QObject 
{ 
    Q_OBJECT 

public: 
    Worker() { } 

public slots: 
    void doWork() 
    { 
     qDebug() << "executing thread id - " << QThread::currentThreadId(); 
    } 
}; 

class WorkerThread : public QThread 
{ 
    Q_OBJECT 

public: 
    void run() 
    { 
     qDebug() << "new thread id " << QThread::currentThreadId(); 
     Worker worker; 
     exec(); 
    } 
}; 
1

ワーカーはメインスレッドで作成されているため、イベントはメインスレッドで処理されます。あなたはそれ自身のスレッドに労働者を移動する必要があります。

Worker worker; 
worker.moveToThread(&worker); 
worker.start(); 

今Qtは新しいスレッドでworker生活を知っているし、そのイベントループ内のイベントをキューに入れます。

関連する問題