Exit QThread Cleanly
-
I am currently developing a GUI front-end application for DVR. After completing the coding part of it, I have tested it many times and it is working fine.
I am using QThread in my code for checking the state of the backend server 24X7. I do not have any proper solution for closing second thread cleanly when my main thread i.e. GUI thread quits.
Here is the code which I have been using right now for second thread.
@void thread::run()
{forever
{
forever
{
checking some condition........
emit <signal>;
break;
}
forever
{
checking some condition........
emit <signal>;
break;
}
}
}@Please suggest any solution for the above scenario.
-
Before I answer your question I will first say that, despite examples given in the docs, it is generally considered a bad idea to subclass QThread and instead create a worker object that is moved into a thread. To stop a QThread you need to call quit() and, if that fails, terminate(). The issue here is that you're running a blocking method and no event loop so these methods will not work on there own. What you therefore need is a flag that is checked on every iteration of the forever loop and set by a signal/slot call from your main thread when the GUI exits. The following files form a minimal working example:
widget.h
@
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
class QThread;
class Widget : public QWidget
{
Q_OBJECTpublic:
explicit Widget(QWidget *parent = 0);
~Widget();private:
QThread *thread;signals:
void stopThread();public slots:
void start();
void tick();
};#endif // WIDGET_H
@widget.cpp
@
#include "widget.h"
#include "threaded.h"#include <QVBoxLayout>
#include <QPushButton>
#include <QThread>
#include <QDebug>Widget::Widget(QWidget *parent) :
QWidget(parent)
{
QVBoxLayout *l=new QVBoxLayout(this);QPushButton *startButton=new QPushButton("Start", this); connect(startButton, SIGNAL(clicked()), this, SLOT(start())); l->addWidget(startButton);
}
Widget::~Widget()
{
if(thread->isRunning()){
emit stopThread();
thread->quit();
if(!thread->wait(5000)){
thread->terminate();
if(!thread->wait(5000)) qDebug() << "Failed to terminate!";
}
}
}void Widget::start(){
thread=new QThread();
Threaded *threaded=new Threaded();
connect(this, SIGNAL(stopThread()), threaded, SLOT(stop()));
connect(threaded, SIGNAL(tick()), this, SLOT(tick()));
connect(thread, SIGNAL(started()), threaded, SLOT(work()));
threaded->moveToThread(thread);
thread->start();
}void Widget::tick(){
qDebug() << "tick";
}
@threaded.h
@
#ifndef THREADED_H
#define THREADED_H#include <QObject>
class Threaded : public QObject
{
Q_OBJECT
public:
explicit Threaded(QObject *parent = 0);private:
bool mStop;signals:
void tick();public slots:
void work();
void stop();
};#endif // THREADED_H
@threaded.cpp
@
#include "threaded.h"#include <QMutex>
#include <QWaitCondition>
#include <QCoreApplication>Threaded::Threaded(QObject *parent) :
QObject(parent), mStop(false)
{}void Threaded::work(){
QMutex dummy;
QWaitCondition waitCondition;forever{ dummy.lock(); waitCondition.wait(&dummy, 1000); emit tick(); dummy.unlock(); QCoreApplication::processEvents(); if(mStop) break; }
}
void Threaded::stop(){
mStop=true;
}
@main.cpp
@
#include <QtGui/QApplication>
#include "widget.h"int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();return a.exec();
}
@Hope this helps ;o)