在无限循环中暂停 QThread

Pausing QThread on infinite loop

我有一个 Qt gui QMainWindow,它有一个 QThread 启动另一个 class.

对象的无限循环

这是简短的代码: 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!),当用户单击恢复按钮时,它会继续计算。 我也阅读了 this 主题,但它没有帮助,因为它使用了 QThread subclass,据我所知。

有人可以帮我吗?

paused 标志与 QMutexQWaitCondition 一起使用。

// 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();

我想,您希望在 thread_1 中调用 cal.run() 方法。抱歉,它将在您当前的 GUI 线程中调用。如果您已将 void run() 声明为 public 插槽,它将通过单独线程中的 Qt::AutoConnection 调用(也许,它只是隐藏在 //many functions! 后面)。

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

您可以使用计时器让 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