Visual studio 2010 暂停并恢复QThread
我最近开始学习QThreads,我有一个程序,在一个单独的线程中运行一个4小时长的循环(这样我就可以继续使用GUI)。我想要的是,当用户单击pause qpushbutton时暂停/挂起线程,当用户单击resume qpushbutton时,程序应该继续。我怎样才能做到这一点Visual studio 2010 暂停并恢复QThread,visual-studio-2010,qt4,qthread,Visual Studio 2010,Qt4,Qthread,我最近开始学习QThreads,我有一个程序,在一个单独的线程中运行一个4小时长的循环(这样我就可以继续使用GUI)。我想要的是,当用户单击pause qpushbutton时暂停/挂起线程,当用户单击resume qpushbutton时,程序应该继续。我怎样才能做到这一点 我想从我的主课上发出信号;但是,我不确定如何在线程中处理它们。可以在线程中处理从主类发送的信号吗?目前,我有线程向主类发送信号,这很好,但我不确定如何从主类发送线程,并在线程中接收它们。好的,因此我建议您创建内部线程变量,
我想从我的主课上发出信号;但是,我不确定如何在线程中处理它们。可以在线程中处理从主类发送的信号吗?目前,我有线程向主类发送信号,这很好,但我不确定如何从主类发送线程,并在线程中接收它们。好的,因此我建议您创建内部线程变量,该变量将在循环的每个步骤中检查+
QWaitCondition
,以继续执行
QWaitCondition
(请参阅Qt文档)暂停线程执行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
}
}
};
为了挂起一个工作线程,我使用了以下方法 以下是我的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::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();
}
这是我的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文件的一部分:
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::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();
}
Worker::Worker(小部件*par){
父=PAR;/ /存储指向GUI线程的指针
计数器=1;//在这里初始化计数器很重要
限额=100000000;
}
void Worker::compute(){
while(计数器<限制){
如果(父->check.testAndSetOrdered(1,2)){//在那里
//如果在GUI线程中将check设置为另一个值,testAndSetOrdered可能会失败。
//如果是这种情况,我们返回,什么也不做
//对于QMutex和QWaitCondition,这种方法在CPU上更容易实现。
//你在这里计算吗
计数器+=1;
父级->检查.testAndSetOrdered(2,1);
//在下一次迭代之前,我们必须恢复
//检查到1,我们不在乎这里是否失败
}否则{
返回;
}
}
//现在,我们准备进行另一轮计算,并通知GUI
//这一轮我们已经结束了。
计数器=1;
发射超过();
}
基本思想是使用QAtomicInt特性。在工作线程中,我们检查check是否保持不变。如果它被改变了,我们就回来,什么也不做。要改变它,我们必须与工作线程竞争从GUI线程进行检查的访问。这就是为什么我们需要whileblock。我们把while块放在resume部分,不过在大多数情况下,第一次尝试就会成功。但是我们正在处理多线程,还记得吗?您的线程是与Qt事件循环一起工作,还是有自己的“工作循环”?谢谢您的建议。我一定会调查情况的。你能允许我在点击按钮时恢复线程吗?因为在这个阶段,我不确定如何将不同线程中的bool值更改为GUI。再次感谢。使用QMutex锁定线程中的成员,更改其值并解锁互斥锁。在您的工作线程锁互斥体(与更改值时的互斥体相同)中,检查值,如果为true,则使用QWaitCondition等待此互斥体。同样适用于“恢复”方法。锁定互斥锁,更改值,解锁互斥锁,唤醒QWaitCondition。你的另一个线程将继续运行!在你的例子和一些文档阅读之后,我想我明白了。最后,我要提到的是,我读到,继承QThread“不好”,所以我继承QObject并使用moveToThread将工作放入新线程中。尽管如此,我相信你的建议会很好!整个“QThread-你做错了”是关于理解QObject线程相关性以及信号是如何传递给QObject的。如果您知道自己在做什么,并且了解qtwead中的工作方式,那么继承QThread也不错。我不是Qt的专家,所以我不会对此发表评论。我相信你知道你在说什么;希望有一天我能更好地理解这些东西是如何工作的。谢谢你的帮助。