Spottsworth
Spottsworth

Reputation: 415

How to listen for a "finished" indication after moving the execution to another thread in Qt

I have a non-GUI operation which I intend to perform in a worker thread. After some googling, I figured out a simple way to achieve this here

In particular, the QMetaObject::invokeMethod() suits me fine. I have also taken care of not sub-classing QThread and instead subclassing QObject to create my worker object and then moving the thread affinity of this object to a newly created thread. (decribed in some detail here

Now my question:

I will begin queuing methods from my main thread (I imagine this happens under the hood using a QEventLoop, even though I have not set one up and even though I have not re-implemented QThread::run() or called QThread::exec()) I need to find out when my worker has finished processing. In other words, I need to know when the QEventLoop is empty. I thought I could use the signal finished() for this. But it does not appear to work. Can someone throw some light on how to find out when a worker thread has finished execution? If you need more info/code, just let me know.

Class Plugin is a subclass of QObject

Plugin::Plugin()
{
    m_workerThread = new QThread(this);
    m_workerThread->start(QThread::IdlePriority);
    m_worker = new DataWorker(this);
    connect(m_workerThread, SIGNAL(finished()), m_worker, SLOT(deleteLater()));    
    m_worker->moveToThread(m_workerThread);
}

...

Plugin::updateData()
{
....
if( true == QMetaObject::invokeMethod(m_worker, "RunFProcToGetData", Qt::QueuedConnection, Q_ARG(QString, foo)))
            {
                qDebug() << "successfully invoked RunFProcToGetData";
            }
            if( true == QMetaObject::invokeMethod(m_worker, "updateDataIntoDB", Qt::QueuedConnection, Q_ARG(QSqlDatabase, db),                                                Q_ARG(QString, foo)))
            {
                qDebug() << "successfully invoked updateDataIntoDB";
            }
....
}

In Dataworker class

Dataworker::RunProcToGetData(const QString &foo)
{
// invoke a program to get the Data
}


Dataworker::updateDataIntoDB(const QSqlDatabase& db, const QString &foo)
{
// Update database 
}

So when there are no more updateDataIntoDB and RunFProcToGetData left to process, I need a trigger

Upvotes: 3

Views: 1142

Answers (1)

Saša Mrvoš
Saša Mrvoš

Reputation: 1

You don't need to re-implement QThread::run(), your code is just fine. Default run() will execute the event loop, and will execute Dataworker slots that are queued (Qt:QueuedConnection). Loop executes infinitely, until you explicitly stop it with thread->quit().

I would recommend you to put some notification signals to the Dataworker class that you will emit from RunFProcToGetData(), updateDataIntoDB(), ... So that you can connect notify signal from the last invoked method in the updateData() to the desired slot (probably in the Plugin). That connection will also be queued (Qt:QueuedConnection is default if objects run in different threads).

That way you'll be notified when all the queued methods from updateData() finish execution. You can than call updateData() multiple times; the m_workerThread will either run queued Dataworker slots or be idle. Remember to stop the thread and wait for it to complete in the destructor of the Plugin:

Plugin::~Plugin() {
    ...
    m_workerThread_->quit();
    m_workerThread_->wait();
    ...
}

Upvotes: 0

Related Questions