6

私のアプリケーションには、メイン スレッドとワーカー スレッド ( 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 が に出力されますQThread doWork

また、単純なプロデューサー・コンシューマーの実装も考えましたが、これがうまくいくなら、このようにしない理由はありますか?

4

5 に答える 5

3

問題は、レシーバー (QThread) がメイン スレッドに「存在」し、メイン スレッドのイベント ループがスロットを実行することでした。

Qtのドキュメントから:

キュー接続では、オブジェクトが属するスレッドのイベント ループに制御が戻ると、スロットが呼び出されます。スロットは、レシーバー オブジェクトが存在するスレッドで実行されます。

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

于 2009-08-01T19:05:21.657 に答える
2

生産者と消費者の単純な例については、Bradley T. Hughes Treading without the頭痛のブログ エントリを参照してください。

于 2009-08-02T08:08:06.363 に答える
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();
    }
};
于 2009-08-11T18:27:16.767 に答える
1

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

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

これで、 Qtworkerは新しいスレッドに存在することを認識し、そのイベント ループでイベントをキューに入れます。

于 2012-06-20T01:59:40.360 に答える
-1

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

于 2009-08-01T18:38:41.787 に答える