Unsolved QThread: is this the correct way to do it, and howto stop the thread and destruct the object?
-
Hi All,
I'm tasked with writing a program that checks for something every 10ms. I have first tried to write it using QTimers in a single threaded program, but all the gui, disk-io and other processing in the GUI thread creates jitter. Therefore I am writing a program that uses the GUI thread for everything but the 10msec task, and a second thread that only runs a qTimer and the slot for the 10ms task. The 10ms task reports it's results once per second to the gui thread using a signal/slot connection.
I have used the approach shown in this blog post: https://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/ and just above the chapter "DOs and DON'Ts" here: https://wiki.qt.io/Threads_Events_QObjects
So in the mainwindow.cpp I create my object:
Then I create a new thread
Then I move my object to the new thread
Then I use the started signal from the thread to start the timer in my object
Finally I start the threadThis is the first multi-threaded program I've ever written, so I would like to know if i have done it right. Also, creating the thread works fine, but what's the correct way to stop the threads when the program ends so there are no memory leaks and all the threads are guarantied to have stopped?
Cheers,
CedricMainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QThread>
#include "datacollector.h"namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{
Q_OBJECTpublic:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void slotData(int Value);
private:
Ui::MainWindow *ui;
DataCollector *myDatacollector = nullptr;
QThread *myThread = nullptr;
};#endif // MAINWINDOW_H
Mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"#include <QDebug>
#include <QThread>MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
qDebug()<<Q_FUNC_INFO << "from" << QThread::currentThread();
ui->setupUi(this);
myDatacollector = new DataCollector();
connect(myDatacollector,&DataCollector::sigData,this,&MainWindow::slotData);
myThread = new QThread;
myDatacollector->moveToThread(myThread);
connect(myThread,&QThread::started,myDatacollector,&DataCollector::slotStart);myThread->start();
}
MainWindow::~MainWindow()
{
qDebug()<<Q_FUNC_INFO << "from" << QThread::currentThread();
delete ui;myThread->quit(); //delete myThread; //delete myDatacollector;
}
void MainWindow::slotData(int Value)
{
qDebug()<<Q_FUNC_INFO << "from" << QThread::currentThread() << " :" << Value;
}datacollector.h
#ifndef DATACOLLECTOR_H
#define DATACOLLECTOR_H#include <QObject>
#include <QTimer>
#include <QDateTime>class DataCollector : public QObject
{
Q_OBJECT
public:
explicit DataCollector(QObject *parent = nullptr);
~DataCollector(void);signals:
void sigData(int value);
public slots:
void slotStart(void);
void slotTimer(void);private:
QTimer *myTimer = nullptr;
QDateTime *myQDateTime = nullptr;
int myValue = 0;
int myJitter = 0;
};#endif // DATACOLLECTOR_H
datacollector.cpp
#include "datacollector.h"
#include <QDebug>
#include <QThread>const int INTERVAL_10MS=10;
DataCollector::DataCollector(QObject *parent) : QObject(parent)
{
qDebug()<<Q_FUNC_INFO << "from" << QThread::currentThread();
myQDateTime = new QDateTime();
}DataCollector::~DataCollector()
{
qDebug()<<Q_FUNC_INFO << "from" << QThread::currentThread();
delete myQDateTime;
myTimer->stop();
delete myTimer;
}void DataCollector::slotStart()
{
qDebug()<<Q_FUNC_INFO << "from" << QThread::currentThread();
if (myTimer == nullptr) //cannot be done in the constructor, as the constructor runs before we move to a worker thread
{
myTimer = new QTimer();
connect(myTimer,&QTimer::timeout,this,&DataCollector::slotTimer);
myTimer->start();
}
}void DataCollector::slotTimer()
{
//do the stuff that has to be done real time//compensate for imperfect timer //Make sure 100 signals per second are fired //also, make sure signals are always fired just after the start of a second //so every function that waits untial some time has passed works as expected. const qint64 OFFSET_FROM_10MS=2; QDateTime nowdt = myQDateTime->currentDateTime(); //qDebug()<<nowdt; qint64 now = nowdt.toMSecsSinceEpoch(); qint64 next = (now + INTERVAL_10MS); next /= INTERVAL_10MS; next *= INTERVAL_10MS; next += OFFSET_FROM_10MS; //next should now be 2 msec after a 10 mc time qint64 interval = next - now; int jitter = static_cast<int>((next - INTERVAL_10MS) - now); jitter = abs(jitter); if (jitter > myJitter) { myJitter = jitter; } myTimer->setInterval(static_cast<int>(interval)); myValue++; if (myValue >= 99) { myValue = 0; sigData(myJitter); myJitter = 0; qDebug()<<Q_FUNC_INFO << "from" << QThread::currentThread(); }
}
-
Hi,
Did you read the current QThread documentation ?
It shows the worker object approach including object deletion.