Visual studio 2010 暂停并恢复QThread

Visual studio 2010 暂停并恢复QThread,visual-studio-2010,qt4,qthread,Visual Studio 2010,Qt4,Qthread,我最近开始学习QThreads,我有一个程序,在一个单独的线程中运行一个4小时长的循环(这样我就可以继续使用GUI)。我想要的是,当用户单击pause qpushbutton时暂停/挂起线程,当用户单击resume qpushbutton时,程序应该继续。我怎样才能做到这一点 我想从我的主课上发出信号;但是,我不确定如何在线程中处理它们。可以在线程中处理从主类发送的信号吗?目前,我有线程向主类发送信号,这很好,但我不确定如何从主类发送线程,并在线程中接收它们。好的,因此我建议您创建内部线程变量,

我最近开始学习QThreads,我有一个程序,在一个单独的线程中运行一个4小时长的循环(这样我就可以继续使用GUI)。我想要的是,当用户单击pause qpushbutton时暂停/挂起线程,当用户单击resume qpushbutton时,程序应该继续。我怎样才能做到这一点


我想从我的主课上发出信号;但是,我不确定如何在线程中处理它们。可以在线程中处理从主类发送的信号吗?目前,我有线程向主类发送信号,这很好,但我不确定如何从主类发送线程,并在线程中接收它们。

好的,因此我建议您创建内部线程变量,该变量将在循环的每个步骤中检查+
QWaitCondition
,以继续执行

  • 创建一个暂停方法,在这里您将打开“暂停字段”(bool?),不要忘记同步它
  • 在您自己的循环中,使用
    QWaitCondition
    (请参阅Qt文档)暂停线程执行
  • 创建恢复方法,在该方法中,您将关闭“暂停字段”并唤醒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
            }
        }
    };
    

  • 为了挂起一个工作线程,我使用了以下方法

    以下是我的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::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();
    }
    
    这是我的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文件的一部分:

    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::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();
    }
    
    Worker::Worker(小部件*par){
    父=PAR;/ /存储指向GUI线程的指针
    计数器=1;//在这里初始化计数器很重要
    限额=100000000;
    }
    void Worker::compute(){
    while(计数器<限制){
    如果(父->check.testAndSetOrdered(1,2)){//在那里
    //如果在GUI线程中将check设置为另一个值,testAndSetOrdered可能会失败。
    //如果是这种情况,我们返回,什么也不做
    //对于QMutex和QWaitCondition,这种方法在CPU上更容易实现。
    //你在这里计算吗
    计数器+=1;
    父级->检查.testAndSetOrdered(2,1);
    //在下一次迭代之前,我们必须恢复
    //检查到1,我们不在乎这里是否失败
    }否则{
    返回;
    }
    }
    //现在,我们准备进行另一轮计算,并通知GUI
    //这一轮我们已经结束了。
    计数器=1;
    发射超过();
    }
    

    基本思想是使用QAtomicInt特性。在工作线程中,我们检查check是否保持不变。如果它被改变了,我们就回来,什么也不做。要改变它,我们必须与工作线程竞争从GUI线程进行检查的访问。这就是为什么我们需要whileblock。我们把while块放在resume部分,不过在大多数情况下,第一次尝试就会成功。但是我们正在处理多线程,还记得吗?

    您的线程是与Qt事件循环一起工作,还是有自己的“工作循环”?谢谢您的建议。我一定会调查情况的。你能允许我在点击按钮时恢复线程吗?因为在这个阶段,我不确定如何将不同线程中的bool值更改为GUI。再次感谢。使用QMutex锁定线程中的成员,更改其值并解锁互斥锁。在您的工作线程锁互斥体(与更改值时的互斥体相同)中,检查值,如果为true,则使用QWaitCondition等待此互斥体。同样适用于“恢复”方法。锁定互斥锁,更改值,解锁互斥锁,唤醒QWaitCondition。你的另一个线程将继续运行!在你的例子和一些文档阅读之后,我想我明白了。最后,我要提到的是,我读到,继承QThread“不好”,所以我继承QObject并使用moveToThread将工作放入新线程中。尽管如此,我相信你的建议会很好!整个“QThread-你做错了”是关于理解QObject线程相关性以及信号是如何传递给QObject的。如果您知道自己在做什么,并且了解qtwead中的工作方式,那么继承QThread也不错。我不是Qt的专家,所以我不会对此发表评论。我相信你知道你在说什么;希望有一天我能更好地理解这些东西是如何工作的。谢谢你的帮助。