c++ – How do I put the current thread to sleep with the ability to resume from another thread in Qt?

Question:

There is a thread that sometimes sleeps ( QThread::sleep ) for quite a long time (about 5 seconds). If the user exits the program, the main thread tries to terminate the sleeping one and waits for it to actually terminate using the QThread::wait function. But 5 seconds is long enough to make the user nervous. In this regard, the question is: how to wake up a thread that has called the QThread::sleep function inside itself?

Answer:

Qt does not provide a means to wake up a sleeping thread. But you can use the QWaitCondition class QWaitCondition with some tweaking. Let's write a special class for this.

WakeableSleep.h:

#ifndef WAKEABLESLEEP_H
#define WAKEABLESLEEP_H
#include <QObject>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
/**
 * @brief Класс, который позволяет временно усыпить поток с возможностью пробуждения из другого потока.
 *
 * Класс можно создать в любом потоке. При вызове метода \ref sleep поток приостанавливается
 * на время, переданное с параметром. При вызове метода \ref wake из другого потока целевой
 * поток возобновляет выполнение независимо от истекшего времени.
 * \threadsafe
 */
class WakeableSleep : public QObject
{
    Q_OBJECT
public:
    explicit WakeableSleep(QObject *parent = 0);
    /**
     * @brief Усыпить текущий поток на milleseconds миллисекунд.
     * @param milliseconds Время сна.
     */
    void sleep(quint32 milliseconds);
    /**
     * @brief wake Пробудить целевой поток из другого потока.
     */
    void wake();
private:
    QMutex mutex;
    QWaitCondition waitCondition;
};
#endif // WAKEABLESLEEP_H

WakeableSleep.cpp:

#include "wakeablesleep.h"
WakeableSleep::WakeableSleep(QObject *parent) :
    QObject(parent){}

void WakeableSleep::sleep(quint32 milliseconds)
{
    mutex.lock();
    waitCondition.wait(&mutex, milliseconds);
    mutex.unlock();
}

void WakeableSleep::wake()
{
    mutex.lock();
    waitCondition.wakeAll();
    mutex.unlock();
}

Now, instead of the QThread::sleep method, you can use the methods of this class as follows:

WakeableSleep sleeper;
void Thread1()
{
    sleeper.wake();
}
void Thread2()
{
    sleeper.sleep(5000);
}
Scroll to Top