1

我的问题是 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() 只是永远等待,因为我的线程不会死。

我不认为信号槽的东西可以用于阻塞,至少我不明白如何。也许有一些不明显的事件技巧。我意识到我可以有一个忙碌的循环检查一些由工作线程操作的标志,但这会使 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意味着invokeMethod将阻塞直到它可以实际调用插槽doNothing()并返回。


您可以运行 aQEventLoop并使其在收到信号时退出:

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 回答