如何阻止运行阻塞永远循环的QThread?

时间:2012-02-11 20:35:11

标签: c++ linux qt

我有一些粗略的代码,我一直在尝试:

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

由于工作线程在带有阻塞IO调用的永久循环中运行,我将如何构造它以便在GUI线程中按下“停止”按钮时,工作线程会干净地停止?

4 个答案:

答案 0 :(得分:4)

当然,你可以在每次迭代检查Worker::run()中的for循环中放置一个布尔值,该值在== true时中断并由gui Stop按钮设置。当然,这不会在执行被阻止时退出线程。

可能更好的是摆脱for循环并使用Qt的信号和插槽来设置回调函数,连接到像QIODevice::readyRead()这样的信号。只有在套接字/管道中有可用信息时才会调用它们。任何其他时间你都可以使用QThread::exit()退出该帖子。您还需要在某个时刻调用QThread::exec()以使事件循环继续。

答案 1 :(得分:0)

首先,您应该设置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()

如果您需要更复杂的管理,那么简单停止,您可能需要使用互斥锁保护您的状态变量。

答案 2 :(得分:0)

要停止工作线程,必须添加“stop requested”布尔标志,该标志应在每次迭代开始时进行测试。此外,还需要同步来读取/写入此布尔标志的值。

这是草稿版本:

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

答案 3 :(得分:0)

Here我认为你解释了你的问题。当您的申请结束时,您应该这样做:

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对于避免死锁情况非常重要。