在无限循环上暂停QThread

时间:2016-03-16 16:13:27

标签: c++ multithreading qt infinite-loop qthread

我有一个Qt gui为QMainWindow,其QThread启动另一个类对象的无限循环。

以下是简要代码: Calculations.h

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

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.h如下:

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

我希望在GUI上有一个暂停按钮,所以当用户点击它时,暂停qthread(绝对GUI不能冻结!),当用户点击Resume按钮时,它会继续计算。 我也读过this主题,但它没有帮助,因为它使用了我理解的QThread子类。

有人可以帮助我吗?

2 个答案:

答案 0 :(得分:3)

您可以使用计时器代替循环使Qthread为您执行循环:

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;

}

pauzerestart都是连接到各自按钮的clicked信号的插槽。

如果您希望它每秒只运行一次,那么您可以将1000而不是0传递给startTimer

答案 1 :(得分:1)

pausedQMutex上使用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;
        }
     }
}

<强>更新

请注意,在您的实现中,您只能在与Qt :: DirectConnection直接连接到信号的插槽中使用signalResultAvailable()。如果你想用Qt :: QueuedConnection将它恢复到主GUI线程,你永远不会得到它。请注意,您在Qt :: DirectConnection中连接的所有内容都在调用者线程中调用,因此您无法在该插槽中更新GUI。

更新2

嗯,还有更多。看看这个结构:

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

我想,您希望在cal.run()中调用thread_1方法。对不起,它将在您当前的GUI线程中调用。如果您已将Qt::AutoConnection声明为公共插槽(可能只是隐藏在void run()后面),则会在单独的线程中通过//many functions!调用它。

再次注意。正如我所提到的,run()中自定义无限循环中发出的信号永远不会转到其他线程。此外,在你的实现中,现在没有办法离开你的线程:QThread::stop()无济于事,因为它只会停止Qt事件循环(你进入你的循环后你永远不会到达,但顺便说一句)但是它不会破坏您的自定义无限循环中的执行。