Пробуждение потока QThread другим потоком

/ Просмотров: 556

Бывает такая ситуация, что поток нужно приостановить на какое-то время. Обычно это решается с помощью методов QThread::sleep, QThread::msleep, QThread::usleep. Однако в этом случае поток не будет никак взаимодействовать с другими потоками. А если возникнет ситуация, что поток нужно немедленно завершить (например, при завершении работы всей программы), то придётся ждать, пока время сна закончится. Время сна может быть довольно большим в зависимости от задачи, и таким образом, завершение работы программы затянется на неопределённый срок. Поэтому возникает задача: сделать такую функцию sleep, которую можно вызвать в целевом потоке для его приостановки, и которую можно прервать из другого потока. Частично для этой задачи подходит класс QWaitCondition, но его придётся немного доработать. Сегодня я покажу, как это сделать.

#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

#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();
}

Использовать этот класс можно следующим образом:

WakeableSleep sleeper;
void Task1()
{
    sleeper.wake();
}
void Task2()
{
    sleeper.sleep(5000);
}
Оставьте комментарий!

Комментарий будет опубликован после проверки

Вы можете войти под своим логином или зарегистрироваться на сайте.

(обязательно)