暂停并恢复QThread

时间:2012-01-31 07:20:58

标签: visual-studio-2010 qt4 qthread

我最近开始学习QThreads,我有一个程序在一个单独的线程中运行一个4小时的循环(这样我可以继续使用GUI)。我所追求的是,​​当用户点击暂停qpushbutton时暂停/暂停线程的东西,当用户点击恢复qpushbutton时,程序应该恢复。我怎么能实现这个目标?

我正在考虑从我的班级发出信号;但是,我不确定如何在线程中处理它们。是否可以处理线程中主类发送的信号?目前,我有线程向主类发出信号,并且工作正常,但我不知道如何从主类发送线程,并在线程中接收它们。

2 个答案:

答案 0 :(得分:14)

好的,所以我建议你制作内部线程变量,在你的循环+ QWaitCondition的每个步骤中检查它以恢复它。

  1. 创建暂停方法,您将在其中打开“暂停字段”(bool?),不要忘记同步它
  2. 在您自己的循环中使用QWaitCondition(请参阅Qt文档)暂停执行线程
  3. 创建简历方法,您将关闭“暂停字段”并唤醒QWaitCondition

    class MyWorker: public QThread
    {
    private:
        QMutex sync;
        QWaitCondition pauseCond;
        bool pause;
    
    public:
        MyWorker(...): pause(false) {}
    
        void resume()
        {
            sync.lock();
            pause = false;
            sync.unlock();
            pauseCond.wakeAll();
        }
    
        void pause()
        {
            sync.lock();
            pause = true;
            sync.unlock();
        }
    
    protected:
        void run()
        {
            while(someCondition) // gues it's your loop
            {
                 sync.lock();
                 if(pause)
                     pauseCond.wait(&sync); // in this place, your thread will stop to execute until someone calls resume
                 sync.unlock();
    
                 // do your operation
            }
        }
    };
    

答案 1 :(得分:1)

要暂停工作线程,我使用了以下方法。

以下是我的GUI.h文件的一部分:

public:
    QAtomicInt check;   //it has to be public to be reachable from a
                        //working thread; we’ll use it as a pause flag
private:
    int receiver;       //internal flag
    QThread *thread;    //we will use thread, won’t we?
    Worker *worker;     //here is where all the work is done
signals:
    void begin();       //we will also need a signal

以下是我的GUI.cpp文件的一部分:

Widget::Widget(){
    receiver = 0;
    check = QAtomicInt(1);    //you may use any number, even 42
    pb = new QPushButton("Start");    //I used a button to start, 
                                    //suspend and resume a working thread
    connect(pb, SIGNAL(clicked()), this, SLOT(start()));
    thread = new QThread;    //who did not read Maya Posch’s blog?
    worker = new Worker(this);    //we need a pointer to this to reach
              //our check flag, remember?
    worker->moveToThread(thread);
    connect(this, SIGNAL(begin()), worker, SLOT(compute()));
    connect(worker, SIGNAL(over()), this, SLOT(ovr()));
    thread->start();
}

void Widget::start() {
    if ( receiver == 0 ) {    //just to remember where we are
        pb->setText("Stop");
        receiver = 1;
        emit begin();    //here we start our heavy job
    } else if ( receiver == 1 ) {    //here we pause it
        pb->setText("Start");
        receiver = 2;
        while ( !(check.testAndSetOrdered(2, 3))) {}

//this is where all the magic is done testAndSetOrdered 
//may fail so we repeat it until it succeeds

    } else {
        pb->setText("Stop");
        receiver = 1;
        while ( !(check.testAndSetOrdered(3, 1))) {}

//first we have to restore check to its normal value. 
//This time we can almost never fail, but just in case 
//I leave the while block here

        emit begin();    //here we resume our job
    }
}

这是我的worker.h文件:

class Worker : public QObject {    //do not ask why I did not inherit from QThread, 
                                   //just read Maya Posch
    Q_OBJECT
public:
    Worker(Widget*);
public slots:
    void compute();    //the only slot here that does it all
signals:
    void over();       //we have to inform the GUI thread that we are over
private:
    int limit, counter;    //it is important to declare counter
    Widget *parent;
};

这是我的worker.cpp文件的一部分:

Worker::Worker(Widget* par) {
    parent = par;    //store a pointer to the GUI thread
    counter = 1;     //it is important to initialize counter HERE
    limit = 100000000;
}

void Worker::compute() {
    while ( counter < limit ) {
        if ( parent->check.testAndSetOrdered(1, 2) ) {  //THERE

//testAndSetOrdered may fail, if check was set to another value in the GUI thread.
//If this is the case, we return and DO NOTHING. Compared to techniques with wait() 
//and QMutex and QWaitCondition, this approach is easier on CPU.

            //do your calculations HERE
            counter += 1;
            parent->check.testAndSetOrdered(2, 1);    

//before the next iteration we have to restore
//check to 1, and we don’t care if we fail here

        } else {
            return;
        }
    }

//now we get ready for yet another round of calculations and inform the GUI 
//thread that we are over with this round.

    counter = 1;
    emit over();
}

基本思想是使用QAtomicInt特殊功能。在工作线程中,我们检查CHECK是否保持不变。如果它被改变了我们返回并且什么也不做。要更改它,我们必须与工作线程竞争从GUI线程访问CHECK。这就是我们需要阻止的原因。我们将while块放在简历部分,但在大多数情况下,它会在第一次尝试时成功。但我们正在处理多线程,还记得吗?