C++ 工作线程中的QTimer
我有一个C++ 工作线程中的QTimer,c++,multithreading,qt,qtimer,C++,Multithreading,Qt,Qtimer,我有一个Worker类,它在另一个线程中执行一些工作,它是使用moveToThread()放置的。在Worker::doWork()方法中,我还创建了一个QTimer,它应该根据任务所需的估计时间发出进度更新 下面是一个例子: ThreadController::ThreadController() { Worker* worker = new Worker; worker->moveToThread(&m_workerThread); // ...
Worker
类,它在另一个线程中执行一些工作,它是使用moveToThread()
放置的。在Worker::doWork()
方法中,我还创建了一个QTimer
,它应该根据任务所需的估计时间发出进度更新
下面是一个例子:
ThreadController::ThreadController()
{
Worker* worker = new Worker;
worker->moveToThread(&m_workerThread);
// ...
m_workerThread.start();
emit startWorker(params); // connected to Worker::doWork()
}
class Worker : public QObject
{
Q_OBJECT
public slots:
Worker::doWork(const QString& params)
{
QTimer* timer = new QTimer(this);
connect( timer, SIGNAL(timeout)), this, SLOT(updateProgress()) );
timer->start(estimateTaskLength() / 100);
// perform work...
}
}
现在,这并没有达到预期的效果。
updateProgress()
插槽仅在工作完成后才开始调用。当计时器过期时,超时事件将排入工作线程的事件队列。但是,工作线程QThread正忙于执行doWork()
,因此无法处理该事件。一旦线程完成doWork
,控件将返回QThread的事件循环,并执行timeout
事件
解决此问题的最简单方法是在执行doWork()
的过程中,以一定的间隔使用QCoreApplication::processEvents()
手动调用事件循环。这将允许QThread更早地执行timeout
事件
或者,您可以使用不同的线程来执行这些估计。如果它们的性能不是太高,您甚至可以使用GUI/主线程。GUI/主线程应保持对事件的“响应”(否则应用程序会挂起),以便及时处理超时事件。这可能取决于Qtimer::timeout和This::updateProgress之间的连接类型
默认情况下,它是一个Qt::AutoConnection,这意味着超时信号将排队等待,直到接收对象准备好处理它为止。也就是说,在嫁妆完成后
如果您使用
connect( timer, SIGNAL(timeout)), this, SLOT(updateProgress()), Qt::DirectConnection );
应立即处理超时信号。(但请确保包含必要的互斥体和内容,因为这是一种典型的情况,例如可能发生并发访问…)
()是否doWork
无法估计任务执行过程中的任务长度?例如,如果doWork
正在复制十个文件,它可以在复制每个文件后估计任务长度。这将消除对计时器的需要。@deGoot不幸的是,不需要,对库函数的一次调用占用了大部分工作时间,所需的时间只能根据传递给该函数的数据大小进行估计。这种方法不起作用。计时器和工作算法在同一个线程中,因此需要定期中断工作算法以更新进度。有一个计时器是没有帮助的,因为如果它获得处理器时间,它只能确定它的时间间隔是否已达到,如果它与工作算法在同一线程中,它将无法得到。不幸的是,doWork()
s的大部分时间都花在对外部库的单个函数调用上,返回所需的时间根据传递给它的数据大小进行估计。如果我可以每隔一段时间调用processEvents()
,我也可以直接更新进度。我假设这两个选项是在GUI线程中的ThreadController
中创建计时器(尽管我不太喜欢这种设计,因为它应该是Workers
报告进度的责任)或者创建一个单独的ProgressReporter
类,并将其从Worker
移动到另一个线程。第三个选项是返回到事件循环(并使用排队调用安排更多的工作运行),但我发现如果大部分工作在另一个库中,这也不是一个选项,那么我看到的唯一选择就是使用一个单独的线程。您可以使用QtConcurrent::run(…)
来启动一个非常简单的线程,它可以定期更新这些估计值。或者,如果您不介意超出Qt的范围,您可以研究特定于操作系统的计时器实现,这些实现可能会提供您想要的功能。例如,在Windows上,您可以使用或。计时器
并且此
应位于同一线程中,因此Qt::AutoConnection
将导致Qt::DirectConnection