I see that such topic was discussed many times, but can't find clear answer to simple situation. I have Worker class running in the own thread where I create timer and want to stop it due to some condition. But I am getting the error:
Timers cannot be stopped from another thread
I fill that am missing some core logic in thread working in Qt. Can someone please explain how to resolve that? Thank you.
Here is the main.cpp
#include <QCoreApplication>
#include <QObject>
#include <QtDebug>
#include "worker.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Worker w;
return a.exec();
}
Worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QTimer>
#include <QThread>
#include <QtDebug>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
private:
QThread t;
QTimer *timer;
int count = 1;
public slots:
void dataTimerFunction();
void onStopTimer(QTimer *t);
signals:
void stopTimer(QTimer *t);
};
#endif // WORKER_H
Worker.cpp
#include "worker.h"
Worker::Worker(QObject *parent) : QObject(parent)
{
this->moveToThread(&t);
QObject::connect(&t, &QThread::finished, this, &QObject::deleteLater);
t.start();
// are we in the new thread from this point, right?
timer = new QTimer();
QObject::connect(timer, &QTimer::timeout, this, &Worker::dataTimerFunction);
QObject::connect(this, &Worker::stopTimer, this, &Worker::onStopTimer);
// QObject::connect(this, &Worker::stopTimer, this, &Worker::onStopTimer, Qt::QueuedConnection); doesn't work as well
timer->start(200);
}
void Worker::dataTimerFunction()
{
qDebug()<<count;
count++;
if (count>5){
emit stopTimer(timer);
//timer->stop();
}
}
void Worker::onStopTimer(QTimer *t)
{
t->stop();
}
The problem is indeed that the timer is not moved to your thread.
Here is a modified worker class, that does what you might want to achieve. It moves the timer also to the thread and then starts and stops it by using signals / slots.
worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QTimer>
#include <QThread>
#include <QtDebug>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
private:
QThread t;
QTimer *timer;
int count = 1;
signals:
void stopTimer();
void startTimer(int msec);
public slots:
void dataTimerFunction();
};
#endif // WORKER_H
worker.cpp
#include "worker.h"
Worker::Worker(QObject *parent) : QObject(parent)
{
// are we in the new thread from this point, right?
timer = new QTimer(nullptr);
this->moveToThread(&t);
timer->moveToThread(&t);
QObject::connect(&t, &QThread::finished, this, &QObject::deleteLater);
t.start();
QObject::connect(timer, &QTimer::timeout, this, &Worker::dataTimerFunction);
QObject::connect(this, &Worker::stopTimer, timer, &QTimer::stop, Qt::QueuedConnection);
QObject::connect(this, &Worker::startTimer, timer, static_cast<void (QTimer::*)(int)>(&QTimer::start), Qt::QueuedConnection);
startTimer(200);
}
void Worker::dataTimerFunction()
{
qDebug()<<count;
count++;
if (count>5){
stopTimer();
}
}