Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QThread - how to stop worker?

Tags:

c++

qt

I'm reading that I should use worker object and move it to thread by moveToThread instead of inherit from QThread directly. But I can't find solution how to stop loop in my object worker. For example I have test loop:

void CollectionWorker::doWork()
{
    for (int i = 0; i < 10; ++i) {
        sleep(1);
        emit ping(i);
    }
}

Now I'm moving this object to thread:

worker->moveToThread(mTh); 

This is working fine. But when I call mTh.quit() then thread is waiting until loop in doWork is end. When I inherit from QThread directly then on each loop I can check thread status and break loop when thred is finished but don't know how to do it in worker object. Can I just create some flag in worker object and switch it from main thread? Or maybe can I find thread owner and check it status? Or maybe better before starting thread, set thread pointer in worker object and then check status? What is the best thread safe solution?

Regards

like image 577
Dibo Avatar asked Mar 28 '26 11:03

Dibo


2 Answers

Calling quit() or exit() on a thread object will simply end the event loop of the thread if there is any running. But As you rightly pointed out, the original problem remains the same. What if the worker function has already been executed by event loop and is a long running function with forever construct. The call to quit() or exit() will simply wait till the worker function returns.

Couple of approaches can be suggested apart from making a public function available to caller which will alter an internal flag.

  • Give a termination signal and slot in your worker class. Something as following.

    signals:
        void signalTermination();
    public slots:
        void setTerminationFlag();
    private:
        QMutex mutex;
        bool terminationRequested;

Your slot would look like something.

void setTerminationFlag()
{
    QMutexLocker locker(&mutex);
    terminationRequested = true;
}

Then you can check the variable in your doWork function in every iteration of forever loop.

mutex.lock();
if(terminationRequested)
{
    //break from loop and effectively doWork function
}
mutex.unlock();

One of the reason of using signals and slots instead of plain member function is that, if your worker function is doing some long running task inside synchronized code block, the public function will remain blocked until it gets access of the synchronization object. This might have adverse effect if the calling thread of your public termination method is UI thread.

  • Another clean and simpler approach if you are using Qt 5.2 onwards

Use requestInterruption() method of QThread. This method sets an advisory flag in the thread object which you can check via isInterruptionRequested() function call in your doWork() function. See following code snippet given in QThread::isInterruptionRequested documentation.

void long_task() {
    forever {
        if ( QThread::currentThread()->isInterruptionRequested() ) {
            return;
        }
    }
}

You can also directly call quit() here to end the event loop of the thread.

like image 154
Chadwick Robbert Avatar answered Mar 29 '26 23:03

Chadwick Robbert


Edit: Sorry i've misunderstood your question.

There are several alternatives. You can create some flag and before each iteration of your processing loop you check if the flag has been set. Or, in the case your processing data in a list/queue maybe you could signal the process to terminate with a special end-of-data element.

like image 35
bruno Avatar answered Mar 30 '26 01:03

bruno



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!