質問

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

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

役に立ちましたか?

解決

問題は、レシーバー(QThread)がメインスレッドで「生きている」ため、メインスレッドのイベントループがスロットを実行するループであるということでした。

Qtのドキュメントから:

  

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

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

他のヒント

この例は、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();
    }
};

単純なプロデューサー/コンシューマーの例については、Bradley T. Hughesのブログエントリをご覧ください頭痛のない歩行

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

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

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top