mohsen_og
mohsen_og

Reputation: 783

Pausing QThread on infinite loop

I have a Qt gui as QMainWindow which has a QThread that starts a infinite loop of the object of another class.

Here is the brief code: Calculations.h

Class Calculations : public QObject
{
public:
//many functions!
void run();
signals:
void signalResultAvailable();
void signalECUQueryTimePassed();
private:
//many things!
}

and Calculations.cpp

void Calculations::run()
{
    while (1)
    {
        unsigned long loopStart = millis();

        //Heavy calculations per second!

        unsigned long loopEnd = millis();
        if ((loopEnd - loopStart) <= 1000)
        {
                delay(1000 - (loopEnd - LoopStart));
                emit signalResultAvailable;
        }
     }
}

MainWindow.his as follows:

Class MainWindow : public QMainWindow
{

private slots:
    on_button_Pause_clicked();
private:
    Calculations cal;
}

MainWindow.cpp:

MainWindow::MainWIndow() : ui(new Ui::MainWindow), cal()
{
    //all the initializations...

    QThread *thread_1 = new Qthread;
    cal.moveToThread(thread_1);
    connect(thread_1, SIGNAL(started()), &cal, SLOT(run()));
    thread_1->start();
}

void MainWindow::on_buttonPause_clicked()
{
    // I want to put the Thread pause HERE!
}

I want to have a Pause button on the GUI, so when the user clicks it pauses the qthread (absolutely GUI must not freeze!) and when a user clicks the Resume button it continues the calculations. I've read this topic as well but it didnt help since it uses the QThread subclass as I understood.

Can anybody please help me?

Upvotes: 3

Views: 1600

Answers (2)

ratchet freak
ratchet freak

Reputation: 48196

You can instead of doing a loop make the Qthread do the looping for you using a timer:

Calculations::Calculations(QObject *parent) :QObject(parent)
{
    timerId = startTimer(0);
}
Calculations::pauze(){
    killTimer(timerId);
    timerId = 0;
}
Calculations.restart(){
    timerId = startTimer(0);
}
Calculations::timerEvent(QTimerEvent *event){


    //Heavy calculations per second!



    emit signalResultAvailable;

}

Both pauze and restart are slots connected to the clicked signal of their respective buttons.

If you want it to run only once per second then you can pass 1000 instead of 0 to startTimer.

Upvotes: 3

Evgeny S.
Evgeny S.

Reputation: 858

Use paused flag with QMutex and QWaitCondition.

// in header
QMutex mutex;
QWaitCondition waitCondition;

// don't forget to false it in constructor
bool paused;

public slots:
   // connect this slot to GUI button toggled(bool) signal
   void setPaused(enable);

...

// in source
void setPaused(bool enable)
{
   mutex.lock();
   paused=enable;
   if (!paused)
      waitCondition.wakeAll();
   mutex.unlock();
}

void Calculations::run()
{
    while (1)
    {
        mutex.lock();
        if (paused)
        {
           waitCondition.wait(&mutex);
        }
        mutex.unlock();

        unsigned long loopStart = millis();

        //Heavy calculations per second!

        unsigned long loopEnd = millis();
        if ((loopEnd - loopStart) <= 1000)
        {
                delay(1000 - (loopEnd - LoopStart));
                emit signalResultAvailable;
        }
     }
}

UPDATE

Note, that in your implementation you can use signalResultAvailable() only in slots directly connected to the signal with Qt::DirectConnection. If you want to get it back to the main GUI thread with Qt::QueuedConnection you will never get it there. And be aware that all that you connect with Qt::DirectConnection is invoked in the caller thread, so you can not update GUI in that slot.

UPDATE 2

Well, there is something more. Look at this construct:

QThread *thread_1 = new Qthread;
cal.moveToThread(thread_1);
connect(thread_1, SIGNAL(started()), &cal, SLOT(run()));
thread_1->start();

I guess, you want the cal.run() method to be invoked in your thread_1. Sorry, it will be invoked in your current GUI thread. It would be invoked via Qt::AutoConnection in the separate thread if you had declared the void run() as public slot (maybe, it is just hidden behind the //many functions!).

And note again. As I've mentioned, your signal emitted in the custom infinite loop in run() will never go to other thread. Moreover, in your implementation now there is no way to leave your thread: QThread::stop() will not help, because it stops only Qt event loop (which you'll never reach, btw, after you enter your loop) but it does not break the execution in your custom infinite loop.

Upvotes: 1

Related Questions