Как остановить QThread, запускающий блокирующий цикл навсегда? - PullRequest
4 голосов
/ 12 февраля 2012

У меня есть грубый код, с которым я экспериментировал:

someserver.cpp (GUI)

#include "server.h"
#include "ui_server.h"

Server::Server(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Server)
{
    ui->setupUi(this);
}

Server::~Server()
{
    delete ui;
}

void Server::onBtnStartClicked()
{
    QThread worker; 
    worker.start(); // Start worker thread that goes into an infinite loop with a blocking call
}

void Server::onBtnExitClicked()
{
    // How do I cleanly stop worker from running?
    QApplication::quit();
}

worker.cpp

#include "worker.h"

Worker::Worker(QObject *parent) :
    QThread(parent)
{
}

void Worker::run()
{
    for (;;)
    {
        // a blocking IO call here like pipe, or msgrcv
        // process data received
    }
}

Поскольку рабочий поток выполняется в цикле навсегда с блокирующим вызовом ввода-вывода, как я смогу структурировать его так, чтобы при нажатии кнопки Stop в потоке GUI рабочий поток останавливался чисто?

Ответы [ 5 ]

4 голосов
/ 12 февраля 2012

Конечно, вы можете поместить логическое значение в цикл for в Worker::run(), проверяемый на каждой итерации, который прерывается на == true и устанавливается кнопкой Стоп графического интерфейса.Конечно, это не приведет к выходу из потока, пока выполнение заблокировано.

Вероятно, лучше избавиться от цикла for и использовать сигналы и слоты Qt для настройки функции обратного вызова, связанной с сигналом типаQIODevice::readyRead().Они будут вызываться только тогда, когда в сокете / канале есть какая-либо информация.В любое другое время вы сможете выйти из темы с помощью QThread::exit().В какой-то момент вам также потребуется вызвать QThread::exec(), чтобы запустить цикл обработки событий.

1 голос
/ 15 июля 2015

в бесконечном цикле вставьте этот код и наслаждайтесь ...

QTime dieTime = QTime::currentTime().addMSecs(1);
while( QTime::currentTime() < dieTime ) {
    QCoreApplication::processEvents( QEventLoop::AllEvents, 1);
}

не забудьте

#include <QCoreApplication>

#include <QTime>

увидимся

0 голосов
/ 16 февраля 2012

Здесь у вас есть объяснение вашей проблемы, я думаю.Когда ваше приложение закончится, вы должны сделать что-то вроде этого:

MyClass::~MyClass()
{
    m_thread->requestStop();
    m_thread->wait(); // Force the thread trying to destroy 
                      // an object of type MyClass, to wait 
                      // the end of the execution of m_thread
    delete m_thread;
}

wait () - решение вашей проблемы с синхронизацией.Вы также можете изменить requestStop() на:

void requestStop()
{
    mutex.lock();
    stopRequested = true;
    mutex.unlock();
    wait();
}

Удаление QMutexLocker важно, чтобы избежать ситуации тупика.

0 голосов
/ 12 февраля 2012

Чтобы остановить рабочий поток, необходимо добавить логический флаг «остановить запрос», который должен проверяться в начале каждой итерации.Также синхронизация необходима для чтения / записи значения этого логического флага.

Вот черновая версия:

class Worker : public QThread {
    public:
        Worker() : stopRequested(false) {}

        void requestStop()
        {
            QMutexLocker locker(&mutex);
            stopRequested = true;
        }

        void run()
        {
            forever
            {
                if (stopRequested())
                    break;

                // a blocking IO call here like pipe, or msgrcv
                // process data received
            }
        }

    private:
        bool stopRequested()
        {
            QMutexLocker locker(&mutex);
            return stopRequested;
        }

        QMutex mutex;
        bool stopRequested;
};
0 голосов
/ 12 февраля 2012

Сначала всего, вы должны установить родительский элемент для Worker, чтобы сделать его дочерним по отношению к другому QObject, правильно очистить его после завершения работы приложения и создать его в куче. то есть динамический путь.

Второй , самый простой способ сделать то, что вы хотите, это определить слот, который будет устанавливать логический член объекта Worker, и проверять его в каждом цикле, чтобы разорвать бесконечный цикл. Не забудьте подключить этот слот к нужному сигналу.

, чтобы вы могли вставить конструктор Server по линиям

QThread * worker = new QThread (this);
connect (this, SIGNAL(terminator()), worker, SLOT(terminate()));

в Server объявление класса:

signals: 
  terminator();

в классе Worker:

private: 
    bool terminate_; // don't forget initialize it to false
public slots: 
    void terminate(){terminate_ = true;}

и в цикле:

if (terminate_) {/* .. do exit things...*/; return; 

после этого отправляйте сигнал terminator() с сервера всякий раз, когда вам нужно.

Если вам потребуется более сложное управление, чем простая остановка, вам, вероятно, потребуется защитить переменную состояния с помощью мьютекса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...