在持久的QThread工作者完成一轮工作的同时,有效地阻止函数执行

时间:2012-04-15 16:45:26

标签: qt qthread

我的问题是,在Qt中似乎没有一种有效的方法可以知道持续 QThread线程何时完成轮次工作。持久性我的意思是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()只是永远等待,因为我的线程不会死。

我不认为信号槽的东西可以用来阻塞,至少我看不出怎么样。也许有一些非明显的事件技巧。我意识到我可以有一个繁忙的wile循环来检查一些由工作线程操纵的标志,但这会使CPU时间远离线程。

如果您知道使用持久性QThread线程阻止的有效方法,我真的很感激如何完成此操作的代码示例。

1 个答案:

答案 0 :(得分:1)

在调用QSemaphore之前,您可以使用带有计数器的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表示invokeMethod将阻止,直到它实际上可以调用广告位doNothing()并返回。


您可以运行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();
}