Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop a qThread in QT [duplicate]

Tags:

c++

qt

qthread

I would like to know how to properly stop a QThread. I havea infinite loop in a thread, and I would like to stop it when I do a specific action :

I have tried :

if (thread->isRunning()){
    worker->stop();
    thread->terminate();
}

the stop() method set a value to false to go out of my infinite loop.

Furthermore, I don't really understand the difference between quit(), terminate() or wait(). Can someone explain me ?

Thanks.

like image 412
iAmoric Avatar asked Mar 08 '17 19:03

iAmoric


1 Answers

A proper answer depends on how you actually use QThread and how you've implemented stop().

An intended use case in Qt assumes following model:

  • You create an object that will do some useful work in response to Signals
  • You create a `QThread` and move your object to this thread
  • When you send a signal to your object, it's processed in `QThread` you've created

Now you need to understand some internals of how this is actually implemented. There are several "models" of signals in Qt and in some cases when you "send a signal" you effectively simply call a "slot" function. That's a "direct" slot connection and in this case slot() will be executed in caller thread, one that raised a signal. So in order to communicate with another thread, Qt allows another kind of signals, queued connections. Instead of calling a slot(), caller leaves a message to object that owns this slot. A thread associated with this object will read this message (at some time later) & perform execution of slot() itself.

Now you can understand what's happening when you create and execute QThread. A newly created thread will execute QThread::run() that, by default, will execute QThread::exec() which is nothing, but an infinite loop that looks for messages for objects associated with thread and transfers them to slots of these objects. Calling QThread::quit() posts a termination message to this queue. When QThread::exec() will read it, it will stop further processing of events, exit infinite loop and gently terminate the thread.

Now, as you may guess, in order to receive termination message, two conditions must be met:

  • You should be running `QThread::exec()`
  • You should exit from slot that is currently running

The first one is typically violated when people subclass from QThread and override QThread::run with their own code. In most cases this is a wrong usage, but it's still very widely taught and used. In your case it seems that you're violating the second requirement: your code runs infinite loop and therefore QThread::exec() simply doesn't get a control and don't have any chance to check that it needs to exit. Drop that infinite loop of yours to recycle bin, QThread::exec() is already running such loop for you. Think how to re-write your code so it does not running infinite loops, it's always possible. Think about your program in terms of "messages-to-thread" concept. If you're checking something periodically, create a QTimer that will send messages to your object and implement a check in your slot. If you processing some large amount of data, split this data to smaller chunks and write your object so it will process one chunk at a time in response to some message. E.g. if you are processing image line-by-line, make a slot processLine(int line) and send a sequence of signals "0, 1, 2... height-1" to that slot. Note that you will also have to explicitly call QThread::quit() once done processing because event loop is infinite, it doesn't "know" when you processed all the lines of your image. Also consider using QtConcurrent for computationally-intensive tasks instead of QThread.

Now, the QThread::terminate() does stop a thread in a very different manner. It simply asks OS to kill your thread. And OS will simply abruptly stop your thread at arbitrary position in the code. Thread stack memory will be free'd, but any memory this stack pointed to won't. If a thread was owning some resource (such as file or mutex), it won't ever release it. An operation that involve writing data to memory can be stopped in the middle and leave memory block (e.g. object) incompletely filled and in invalid state. As you might guess from this description, you should never, ever call ::terminate() except for very rare cases where keeping running of thread is worse than getting memory & resource leaks.

QThread::wait() is just a convenience function that waits until QThread ceases to execute. It will work both with exit() and terminate().

You can also implement a threading system of your own subclassed from QThread and implement your own thread termination procedure. All you need to exit a thread is, essentially, just to return from QThread::run() when it becomes necessary and you can't use neither exit() nor terminate() for that purpose. Create your own synchronization primitive and use it to signal your code to return. But in most cases it's not a good idea, keep in mind that (unless you work with QEventLoop by yourself), Qt signal and slots won't be working properly in that case.

like image 188
Sergei Ozerov Avatar answered Nov 12 '22 17:11

Sergei Ozerov