1

私の問題は、永続的なQThread スレッドが一連の作業を完了したことを知るための効率的な方法が Qt にないように見えることです。永続的とは、QThreads がいくつかの作業を完了した後に死なないことを意味します。

このスレッド スタイルで永続スレッドを使用しています。

class Worker : public QObject
{
    Q_OBJECT

public slots:
    void doWork() {
        /* ... */
    }
};

QThread *threadA = new QThread;
QThread *threadB = new QThread;
Worker *workerA = new Worker;
Worker *workerB = new Worker;
workerA->moveToThread(threadA);
workerB->moveToThread(threadB);
threadA->start();
threadB->start();
QMetaObject::invokeMethod(workerA, "doWork", Qt::QueuedConnection);
QMetaObject::invokeMethod(workerB, "doWork", Qt::QueuedConnection);

私はそのようなシナリオを持っています:

//Outside force (OS/driver) calls this very frequently.
//Gets called a lot so want to re-use threads instead of creating new 
//threads each time.
C callback function(some parameters)  
{  
   //STEP 1
   //Feed 2 threads with computational expensive work.
   //threads should be pre-made threads to save time on thread creation.
   //do not terminate threads because they will be re-used next time C callback
   //function
   //is called with a new round of work.

    //STEP 2
    //Need to pause/wait/BLOCK function execution here until the 2 worker threads
    //have completed the work.
    //THIS IS THE PROBLEM! No efficient way to block! I don't see how a signal/slot
    //can be used for this purpose.

    //STEP3  
    //After 2 threads complete their assigned work, resume execution of this C
    //callback function.  
    //Perform some non-threaded work in this function to complete the job.

    //return (end function execution), all work for this round/call is complete.
}

問題は、上記の疑似コードで説明したように、PERSISTENTスレッドではブロックする方法がないことです。

QThread::wait() を呼び出すことはできません。これは、NON-PERSISTENT THREADS シナリオで作業が完了するまでブロックするためにしか使用できないためです。wait() は、スレッドが死ぬまで待機します...私のニーズには役に立ちません。私の場合、スレッドが死なないため、wait() は永遠に待機します。

シグナルスロットをブロックに使用できるとは思いません。少なくとも方法はわかりません。たぶん、いくつかの非自明なイベント トリックがあります。ワーカー スレッドによって操作されるいくつかのフラグをチェックするビジー ワイル ループが発生する可能性があることに気付きましたが、これにより CPU 時間がスレッドから奪われます。

永続的な QThread スレッドでブロックする効率的な方法を知っている場合は、その方法を示すコード サンプルを提供していただければ幸いです。

4

1 に答える 1

1

QSemaphoreへの呼び出しの前にカウンターを 0 にして を使用できますdoWork。メイン スレッドは待機し、作業が完了するsemaphore.acquire(2);と各ワーカーが呼び出しますsemaphore.release(1);。そのため、メイン スレッドは 2 つのワーカーが完了したときにのみ起動します。


Worker作業を開始した後に呼び出す、オブジェクトで 何もしないスロットを追加できます。

QMetaObject::invokeMethod(workerA, "doWork", Qt::QueuedConnection);
QMetaObject::invokeMethod(workerB, "doWork", Qt::QueuedConnection);

QMetaObject::invokeMethod(workerA, "doNothing", Qt::BlockingQueuedConnection;
QMetaObject::invokeMethod(workerB, "doNothing", Qt::BlockingQueuedConnection);

実際にスロットを呼び出して戻ることができるまでブロックするQt::BlockingQueuedConnection手段。invokeMethoddoNothing()


a を実行してQEventLoop、シグナルを受信したときに終了させることができます。

QEventLoop loop;
// the connection have to be made before running the tasks
// to avoid race condition in case the task is very short
loop.connect(workerA, SIGNAL(finished()), &loop, SLOT(quit()));
loop.connect(workerB, SIGNAL(finished()), &loop, SLOT(quit()));

QMetaObject::invokeMethod(workerA, "doWork", Qt::QueuedConnection);
QMetaObject::invokeMethod(workerB, "doWork", Qt::QueuedConnection);

// the loop will be interrupted once for each worker   
for(int i=0; i < 2; ++i) {
    loop.exec();
}
于 2012-04-16T02:29:45.750 に答える