How can I wake up a QThread when it is sleeping?
I have a thread that is running in the background and now and then wakes up and does some small stuff, however if I would like to stop that thread in a controlled manner I have to wait for him to wake up by him self in order to make him quit. And since he is sleeping quite long this can be quite annoying.
Here is a little example code that show the basic problem.
Let's start with the thread that in this example sleeps for 5 seconds and then just prints a dot.
#include <QDebug>
#include "TestThread.h"
void TestThread::run()
{
running = true;
while(running == true)
{
qDebug() << ".";
QThread::sleep(5);
}
qDebug() << "Exit";
}
void TestThread::stop()
{
running = false;
}
Then we have the main that starts the thread and then kills him.
#include <QDebug>
#include "TestThread.h"
int main(int argc, char *argv[])
{
qDebug() << "Start test:";
TestThread *tt = new TestThread();
tt->start();
sleep(2);
tt->stop();
tt->wait();
delete tt;
}
The problem is that the tt->wait(); must wait the 5s that the thread is sleeping. Can I just call something like a "wakeup from sleep" so he can continue.
Or is there a better way to do this?
/Thanks
Update I got it working with a QMutex and the tryLock:
#include <QDebug>
#include "TestThread.h"
QMutex sleepMutex;
void TestThread::run()
{
qDebug() << "Begin";
//1. Start to lock
sleepMutex.lock();
//2. Then since it is locked, we can't lock it again
// so we timeout now and then.
while( !sleepMutex.tryLock(5000) )
{
qDebug() << ".";
}
//4. And then we cleanup and unlock the lock from tryLock.
sleepMutex.unlock();
qDebug() << "Exit";
}
void TestThread::stop()
{
//3. Then we unlock and allow the tryLock
// to lock it and doing so return true to the while
// so it stops.
sleepMutex.unlock();
}
But would it be better to use the QWaitCondition? Or is it the same?
Update: The QMutex breaks if it is not the same tread that starts and stop him, so here is a try with QWaitCondition.
#include <QDebug>
#include <QWaitCondition>
#include "TestThread.h"
QMutex sleepMutex;
void TestThread::run()
{
qDebug() << "Begin";
running = true;
sleepMutex.lock();
while( !waitcondition.wait(&sleepMutex, 5000) && running == true )
{
qDebug() << ".";
}
qDebug() << "Exit";
}
void TestThread::stop()
{
running = false;
waitcondition.wakeAll();
}
You can use std::promise/std::future as a simpler alternative to a bool / condition_variable / mutex in this case. A future is not susceptible to spurious wakes and doesn't require a mutex for synchronisation. Save this answer.
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.
Instantiating QThread provides a parallel event loop. An event loop allows objects owned by the thread to receive signals on their slots, and these slots will be executed within the thread. On the other hand, subclassing QThread allows running parallel code without an event loop.
Detailed Description. A QThread object manages one thread of control within the program. QThreads begin executing in run(). By default, run() starts the event loop by calling exec() and runs a Qt event loop inside the thread. You can use worker objects by moving them to the thread using QObject::moveToThread().
I don't think that a portable solution exists (though there might be some facilities in some operation systems, like POSIX signals). Anyway, Qt itself doesn't provide such means, thus you could simulate it like
void TestThread::run()
{
running = true;
while(running == true)
{
qDebug() << ".";
// Quantize the sleep:
for (int i = 0; i < 5 && running; ++i) QThread::sleep(1);
}
qDebug() << "Exit";
}
But the best solution would still be a QWaitCondition, as pointed out by Mat.
You could use a QWaitCondition
rather than a simple sleep
. If gives you much more control.
Example usage here: Wait Conditions Example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With