Pause and resume QThread

I recently started learning QThreads, and I have a program that runs for 4 hours in a separate thread (so that I can continue to use the GUI). What I follow is what will pause / pause the stream when the user presses the pause qpushbutton button, and when the user presses the qpushburn button, the program should resume. How can I achieve this?

I was thinking about signaling from my main class; however, I am not sure how I can handle them in a thread. Is it possible to process signals sent from the main class in the stream? I currently have a stream emitting signals to the main class, and this works fine, but I'm not sure how to go about transmitting streams from the main class and getting them in the stream.

+5
source share
2 answers

Ok, so I suggest you make an internal thread variable that will be checked at every step of your + cycle QWaitConditionto resume it.

  • Create a pause method in which you enable the "pause field" (bool?), Do not forget to synchronize it.
  • In your own loop use QWaitCondition(see Qt docs) to pause thread execution
  • Create a resume method in which you turn off the “pause field” and wake up 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 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
            }
        }
    };
    
+14
source

To pause the workflow, I used the following approach.

Here is part of my GUI.h file:

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

Here is part of my GUI.cpp file:

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

Here is my worker.h file:

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

Here is part of my worker.cpp file:

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. , . , CHECK GUI. . , . , ?

+1

All Articles