Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt - how to kill QThread

Tags:

qt

I'm trying to kill/cancel a QThread. I followed the implementation of https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

I create the QThread like this:

workerThread = new QThread();
ImageProcessor* worker = new ImageProcessor();
worker->moveToThread(workerThread);
connect(workerThread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), workerThread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
workerThread->start();

and try to stop it on a certain UI event by calling:

workerThread->quit();

My worker looks like this:

class ImageProcessor : public QObject
{
Q_OBJECT
public:
explicit ImageProcessor(QObject *parent = 0);
~ImageProcessor();

signals:
void finished();

public slots:
void process();

private:
//...
};

Where process calls an API with heavy calculations

void ImageProcessor::process()
{
// API call...

emit finished();
}

My problem is, that after calling quit on the thread, the thread keeps running ie the calculations of the API don't stop. Because the worker only calls the API, I cannot work with a cancel check in the worker loop. Any ideas?

Thanks in advance!

like image 459
the_max Avatar asked Jan 06 '13 11:01

the_max


People also ask

How do you stop QThread in Qt?

QThread will notify you via a signal when the thread is started() and finished(), or you can use isFinished() and isRunning() to query the state of the thread. You can stop the thread by calling exit() or quit(). In extreme cases, you may want to forcibly terminate() an executing thread.

How do you use QThread?

To use it, prepare a QObject subclass with all your desired functionality in it. Then create a new QThread instance, push the QObject onto it using moveToThread(QThread*) of the QObject instance and call start() on the QThread instance. That's all.


2 Answers

Your heavy task is so simple that I would use QtConcurrent::run and forget about QThread.

ImageProcessor* worker = new ImageProcessor();
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
QtConcurrent::run(worker, &ImageProcessor::process);

This does exactly what you need and it will be even a bit faster since it will use thread from thread pool, instead creating a new thread.

Just remember to use Qt::AutoConnection (default value).

To stop processing gracefully you have to do a poling of some variable in your process method:

bool ImageProcessor::needEndNow() {
    QMutexLocker locker(mutex);
    return endNowRequested;
}

void ImageProcessor::requestEndNow() {
    QMutexLocker locker(mutex);
    endNowRequested = true;
}

void ImageProcessor::process()
{
   while(!needEndNow()) {
       // nextStep of processing
   }

   emit finished();
}
like image 176
Marek R Avatar answered Sep 18 '22 02:09

Marek R


If you have something like this, without any loop:

void ImageProcessor::process()
{
    worker_api(); // that takes a lot of time
    emit finished();
}

There is little you can do with QThread. You can do, from probably better to worst:

  • Maybe the API you are using has another call to stop that worker call. But since you are asking here, I guess there is no such thing.
  • Launch the worker call from a different process using QProcess and kill it when no longer needed. Pros: no worries about clean-up. Contras: retrieving results may be difficult.
  • QThread::terminate, but is unadvised (see the warnings in the documentation: basically, no clean-up).
  • In Windows, QThread::currentThreadId gives you a number you may be able to use with other OS calls (see the warnings in the documentation).
like image 37
dmcontador Avatar answered Sep 18 '22 02:09

dmcontador