我最近开始学习QThreads,我有一个程序在一个单独的线程中运行一个4小时的循环(这样我可以继续使用GUI)。我所追求的是,当用户点击暂停qpushbutton时暂停/暂停线程的东西,当用户点击恢复qpushbutton时,程序应该恢复。我怎么能实现这个目标?
我正在考虑从我的班级发出信号;但是,我不确定如何在线程中处理它们。是否可以处理线程中主类发送的信号?目前,我有线程向主类发出信号,并且工作正常,但我不知道如何从主类发送线程,并在线程中接收它们。
答案 0 :(得分:14)
好的,所以我建议你制作内部线程变量,在你的循环+ QWaitCondition
的每个步骤中检查它以恢复它。
QWaitCondition
(请参阅Qt文档)暂停执行线程创建简历方法,您将关闭“暂停字段”并唤醒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's 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
}
}
};
答案 1 :(得分:1)
要暂停工作线程,我使用了以下方法。
以下是我的GUI.h文件的一部分:
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
以下是我的GUI.cpp文件的一部分:
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
}
}
这是我的worker.h文件:
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;
};
这是我的worker.cpp文件的一部分:
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是否保持不变。如果它被改变了我们返回并且什么也不做。要更改它,我们必须与工作线程竞争从GUI线程访问CHECK。这就是我们需要阻止的原因。我们将while块放在简历部分,但在大多数情况下,它会在第一次尝试时成功。但我们正在处理多线程,还记得吗?