Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wake up a QThread that is in sleep?

Tags:

c++

qt

qthread

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();
}
like image 566
Johan Avatar asked Jul 15 '11 10:07

Johan


People also ask

How do you wake up a STD thread while it's asleep?

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.

How do you stop a QThread?

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.

Does QThread have event loop?

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.

What is a QThread?

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().


2 Answers

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.

like image 33
vines Avatar answered Nov 02 '22 00:11

vines


You could use a QWaitCondition rather than a simple sleep. If gives you much more control.

Example usage here: Wait Conditions Example

like image 95
Mat Avatar answered Nov 01 '22 23:11

Mat