Pregunta

I have a Worker class which does some work in another thread, where it's placed using moveToThread(). Inside Worker::doWork() method I also create a QTimer which is supposed to emit progress updates, based on the estimated time the task will take.

Here's an example:

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...
    }
}

Now this doesn't work as intended. The updateProgress() slot only starts being called AFTER the work has been completed.

¿Fue útil?

Solución

When the timer expires, the timeout event is queued to the event queue of your worker QThread. However, your worker QThread is busy executing doWork(), so the event can't be processed. Once the thread completes the doWork, control returns the the QThread's event loop and the timeout event is executed.

The simplest approach to fixing this would be to manually invoke the event loop using QCoreApplication::processEvents() at certain intervals throughout the execution of doWork(). This will allow the QThread to execute the timeout event earlier.

Alternative, you can use a different thread to perform these estimations. If they are not too performance-intensive, you can even use the GUI/main thread. The GUI/main thread is expected to remain "responsive" to events (otherwise the application appears to hang) so it can process the timeout event in a timely manner.

Otros consejos

This probably depends on the type of connection between Qtimer::timeout and this::updateProgress.

By default, its a Qt::AutoConnection, which means that the timeout signal will be queued until the receiving object is ready to handle it. I.e. after doWork is finished.

If you connect using

connect( timer, SIGNAL(timeout)), this, SLOT(updateProgress()), Qt::DirectConnection );

the timeout signal should be treated immediately. (Make sure to include necessary mutexes and stuff though, as this is a typical case where e.g. concurrent accesses may occur..)

( http://qt-project.org/doc/qt-4.8/qt.html#ConnectionType-enum )

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top