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