Multithreading 使用QWaitCondition唤醒线程

Multithreading 使用QWaitCondition唤醒线程,multithreading,qt,mutex,Multithreading,Qt,Mutex,我的Qt应用程序有一个工作线程,在可用时处理新数据。到目前为止,工作线程使用QWaitCondition在新数据可用时唤醒 但是,QWaitCondition仅在线程通过wait()主动等待时触发。虽然新数据在线程仍在工作时可用,或者在它运行到下一个wait()命令之前可用,但可能会发生这种情况 我在MFC中寻找类似CEvent的东西,它可以随时“记住”新数据通知,并且在上次wait()调用后发出新数据信号时不会等待。在Qt中实现这一点的最佳方法是什么 谢谢, FabianQWaitCondit

我的Qt应用程序有一个工作线程,在可用时处理新数据。到目前为止,工作线程使用QWaitCondition在新数据可用时唤醒

但是,QWaitCondition仅在线程通过wait()主动等待时触发。虽然新数据在线程仍在工作时可用,或者在它运行到下一个wait()命令之前可用,但可能会发生这种情况

我在MFC中寻找类似CEvent的东西,它可以随时“记住”新数据通知,并且在上次wait()调用后发出新数据信号时不会等待。在Qt中实现这一点的最佳方法是什么

谢谢,
Fabian

QWaitCondition应与QMutex一起使用

public void Worker::add(Data data)
{
    QMutexLocker lock(&mutex);
    //add data
    condition.wakeOne();
}


public void Worker::run()
{
    while(true)
    {
        Data data;
        {
            // no other thread will be able to trigger a wake while inside this block
            QMutexLocker lock(&mutex);
            if(shouldStop)return;
            while(!hasAvailable()) 
                condition.wait(&mutex);
            data = removeOne();
        }
        //do something with data;

    }
}
这样,如果新数据包出现,线程将不会
等待
,而
wakeOne
将不会被while签入和等待调用之间的另一个线程触发


更好的选择是使用信号和插槽

如果其他线程可以在新数据进入时发出信号,则可以实现一个简单的调度程序类,以便在适当的时间唤醒线程(使用@ratchet freak建议的信号/插槽):


如果在worker运行时输入多个数据值,则这些数据值将由qt事件队列正确排队。调度程序必须位于自己的线程中。信号startWorker必须连接到工作线程中的正确插槽,工作线程的已完成插槽必须连接到OnThreadFinished()插槽。

您可以使用QSemaphore。谢谢。如果“数据”本地存储在线程中,那么它就可以在数据仍然存在时跳过等待。在我的例子中,收集要处理的数据更为棘手,只有在线程被唤醒之后才会发生。在这种情况下,如果我理解正确,上述代码将“忘记”在“使用数据做点什么”部分中触发的唤醒调用。>>更好的选择是使用信号和插槽,这可能是最简单的解决方案。提供一个获取新数据通知的插槽(bNewData=true),并在没有新数据可用时在while循环中睡眠。实际上,如果存在事件循环,则您不会睡眠,因为信号到达时事件循环会自动唤醒。如果没有事件循环,则不会触发插槽。尽管排队的信号插槽连接总是首选,但这是通过
QThreadPool
+
QRunnable
模式实现的唤醒工作线程的常见问题的合理解决方案。由于
QRunnable
没有子类化
QObject
,因此排队的信号插槽连接不能用于唤醒基于
QRunnable
的工作者。在这种特定情况下,
QMutex
+
QWaitCondition
可能是最不疯狂的解决方案。谢谢。然而,我不认为我需要一个专门的调度程序来实现这个目的。。。对我来说,听起来有点过分了。@Fabian,这取决于你怎么想,我非常喜欢“模块化越多越好”的概念,而不是10个小类/函数,然后是一个大类/函数。因此,只要某些功能可以很容易地进行封装,那么对其进行实际封装决不会过分。专用调度程序在任何资源上都不会很昂贵,同时它允许将所有调度保持在一个位置,并且可以在需要时为任何工作人员重用,还可以使工作人员代码不那么繁忙。您的配置是有意义的。我将把你的答案标记为解决方案。感谢所有的反馈。
class Data;
class Scheduler : public QObject
{
Q_OBJECT
public:

Scheduler(QTread* workerIn) : worker(workerIn) {};

Q_SLOT void OnNewData(Data* data)
{
QMutexLocker lock(&mutex);
while(worker->isRunning())
   condition.wait(&mutex);

Q_EMIT startWorker(data);
}; 

Q_SLOT void OnThreadFinished() 
{
     condition.wakeOne();
}

Q_SIGNAL void startWorker(Data* data);    

private:
QThread* worker;
QWaitCondition condition;
QMutex mutex;
};