在无限循环中暂停 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
标志与 QMutex
和 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();
我想,您希望在 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;
}
pauze
和restart
都是插槽,连接到各自按钮的clicked
信号。
如果您希望它每秒仅 运行 一次,那么您可以将 1000 而不是 0 传递给 startTimer
。
我有一个 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
标志与 QMutex
和 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();
我想,您希望在 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;
}
pauze
和restart
都是插槽,连接到各自按钮的clicked
信号。
如果您希望它每秒仅 运行 一次,那么您可以将 1000 而不是 0 传递给 startTimer
。