I need to start and stop a thread very frequently using push button..I am using Qt. Recently I learned to create a QObject of the worker and move it to the object of the QThread as the correct way of implementing threads in Qt. Following is my implementation...
Worker.h
class worker : public QObject
{
Q_OBJECT
public:
explicit worker(QObject *parent = 0);
void StopWork();
void StartWork();
bool IsWorkRunning();
signal:
void SignalToObj_mainThreadGUI();
public slots:
void do_Work();
private:
void Sleep();
volatile bool running,stopped;
QMutex mutex;
QWaitCondition waitcondition;
};
Worker.cpp
worker::worker(QObject *parent) :
QObject(parent),stopped(false),running(false)
{
}
void worker::do_Work()
{
running = true;
while(!stopped)
{
emit SignalToObj_mainThreadGUI();
Sleep();
}
}
void worker::Sleep()
{
mutex.lock();
waitcondition.wait(&mutex,10);
mutex.unlock();
}
void worker::StopWork()
{
mutex.lock();
stopped = true;
running = false;
mutex.unlock();
}
void worker::StartWork()
{
mutex.lock();
stopped = false;
running = true;
mutex.unlock();
}
bool worker::IsWorkRunning()
{
return running;
}
MainWindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
private slots:
void on_pushButton_push_to_start_clicked();
void on_pushButton_push_to_stop_clicked();
private:
Ui::MainWindow *ui;
worker *myWorker;
QThread *WorkerThread;
};
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
myWorker = new worker;
WorkerThread = new QThread;
myWorker.moveToThread(WorkerThread);
QObject::connect(WorkerThread,SIGNAL(started()),myWorker,SLOT(do_Work()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_push_to_start_clicked()
{
if(!myWorker.IsWorkRunning())
{
myWorker->StartWork();
WorkerThread->start();
}
}
void MainWindow::on_pushButton_push_to_stop_clicked()
{
if(myWorker.IsWorkRunning())
{
myWorker->StopWork();
WorkerThread->quit();
}
}
Initially the application works fine but after some operations of the push button to turn the working of the thread on and off the following error comes up...
QObject::killTimers(): timers cannot be stopped from another thread
I am quite puzzled at this error...do I need to implement the start/stop functions as signals and slots rather than member functions of the class?
Don't start and stop WorkerThread
. Just leave it running. Also, move your StartWork()
and StopWork()
methods to the public slots section. You really don't need the mutex at all.
Worker.h
class worker : public QObject
{
Q_OBJECT
public:
explicit worker(QObject *parent = 0);
signal:
void SignalToObj_mainThreadGUI();
void running();
void stopped();
public slots:
void StopWork();
void StartWork();
private slots:
void do_Work();
private:
volatile bool running,stopped;
};
Worker.cpp
worker::worker(QObject *parent) :
QObject(parent), stopped(false), running(false)
{}
void worker::do_Work()
{
emit SignalToObj_mainThreadGUI();
if ( !running || stopped ) return;
// do important work here
// allow the thread's event loop to process other events before doing more "work"
// for instance, your start/stop signals from the MainWindow
QMetaObject::invokeMethod( this, "do_Work", Qt::QueuedConnection );
}
void worker::StopWork()
{
stopped = true;
running = false;
emit stopped();
}
void worker::StartWork()
{
stopped = false;
running = true;
emit running();
do_Work();
}
MainWindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void startWork();
void stopWork();
private slots:
void on_pushButton_push_to_start_clicked();
void on_pushButton_push_to_stop_clicked();
private:
Ui::MainWindow *ui;
worker *myWorker;
QThread *WorkerThread;
};
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
myWorker = new worker;
WorkerThread = new QThread;
myWorker.moveToThread(WorkerThread);
connect( this, SIGNAL(startWork()), myWorker, SLOT(StartWork()) );
connect( this, SIGNAL(stopWork()), myWorker, SLOT(StopWork()) );
}
void MainWindow::on_pushButton_push_to_start_clicked()
{
emit startWork();
}
void MainWindow::on_pushButton_push_to_stop_clicked()
{
emit stopWork();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With