Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 工作线程中的QTimer_C++_Multithreading_Qt_Qtimer - Fatal编程技术网

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