Разбудить QThread, который находится в спящем режиме?

Как я могу разбудить QThread, когда он спит?

У меня есть поток, который работает в фоновом режиме и время от времени просыпается и выполняет некоторые мелкие действия, однако, если я хочу остановить этот поток контролируемым образом, мне нужно дождаться, пока он проснется сам, чтобы заставить его бросить. А так как он спит довольно долго, это может сильно раздражать.

Вот небольшой пример кода, показывающий основную проблему.

Начнем с потока, который в этом примере спит 5 секунд, а затем просто печатает точку.

#include <QDebug>
#include "TestThread.h"

void TestThread::run()
{
    running = true;
    while(running == true)
    {
        qDebug() << ".";
        QThread::sleep(5);
    }
    qDebug() << "Exit";
}

void TestThread::stop()
{
    running = false;
}

Затем у нас есть основной, который запускает поток, а затем убивает его.

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

Проблема в том, что tt->wait(); должен ждать 5 секунд, пока поток спит. Могу ли я просто вызвать что-то вроде "пробуждение ото сна", чтобы он мог продолжить.

Или есть лучший способ сделать это?

/Спасибо


Обновление Я заработал с QMutex и 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();
}

Но не лучше ли использовать QWaitCondition? Или это то же самое?


Обновление: QMutex ломается, если это не тот протектор, который его запускает и останавливает, так что попробуйте с 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();
}

person Johan    schedule 15.07.2011    source источник


Ответы (2)


Вы можете использовать QWaitCondition вместо простого sleep. Если дает вам гораздо больше контроля.

Пример использования здесь: Пример условий ожидания

person Mat    schedule 15.07.2011
comment
Посмотрите на пример, который я связал. Идея состоит в том, чтобы заблокировать мьютекс и использовать функцию wait(QMutex*,long) условия ожидания, чтобы заменить ваш сон, и использовать wakeAll() или wakeOne() в вашей функции stop(). Ваше редактирование нехорошо: вы не должны вызывать lock() из одного потока и unlock() из другого для одного и того же объекта мьютекса. - person Mat; 15.07.2011
comment
Так ты никогда его не разблокируешь? Вы держите bool включенным, чтобы остановить цикл? - person Johan; 15.07.2011

Я не думаю, что существует переносимое решение (хотя в некоторых операционных системах могут быть некоторые возможности, такие как сигналы POSIX). Во всяком случае, сам Qt не предоставляет таких средств, поэтому вы можете смоделировать его, как

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";
}

Но лучшим решением все равно будет QWaitCondition, как указал Мат.

person vines    schedule 15.07.2011