How to run a timer inside a QThread?

Rsvay picture Rsvay · Sep 23, 2013 · Viewed 15.4k times · Source

I would like to run a timer inside a QThread. I have written some code in which i am getting some error during the run time. Please guide me into the right direction. What am I doing wrong?

(Parent is QThread(0x1498d10), parent's thread is QThread(0x11272b0), current thread is QThread(0x1498d10)

mainwindow.h //main .h file

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "mythread.h"
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    MyThread *myt;

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp //main .cpp file

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    myt=new MyThread();
    myt->start();
    MainWindow w;
}

MainWindow::~MainWindow()
{
    delete ui;
}

mythread.h // class for thread

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QTimer>
class MyThread:public QThread
{
public:
    MyThread();
    void run();
   QTimer *thr;
public slots:
   void slo();
};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"

MyThread::MyThread()
{
    thr= new QTimer();
    connect(thr,SIGNAL(timeout()),this,SLOT(slo()));
}
 void MyThread::run()
 {
    thr->start(1000);
 }
void MyThread::slo()
{
    int i,j=0;
    i=i+j;
}

Answer

fbucek picture fbucek · Sep 23, 2013

Just my humble opinion - Do not to subclass QThread anymore, when you do not need to.

I think, you just want to run your class in new thread or more probably you do not want to block other tasks. Your class is not thread itself. Subclassing basically means that your class IS what you are subclassing.

In other words: Let QThread do its job and concentrate on your class to do what it should do.

Example: MyClass itself does not know anything about threads. It just do what it has to do. Incrementing value and showing results ( plus some sleep part to show how it can block other functions or gui )

Header file

#include <QTimer>
#include <QObject>
class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(bool willSleep, QString name, QObject *parent = 0);
public slots:
    void updateCount();
private:
    QTimer *timer;
    int count;
    bool m_wantToSleep;

};

Implementation

#include "myclass.h"
#include <QDebug>

MyClass::MyClass(bool wantToSleep, QString name, QObject *parent) :
    QObject(parent)
{
    this->setObjectName(name);
    m_wantToSleep = wantToSleep;
    count = 0;
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateCount()));
    timer->start(100);
}

void MyClass::updateCount()
{
    ++count;
    qDebug() << objectName() << " count: " << count;
    if (m_wantToSleep)
        sleep(1);
}

We have code which does the job.

Now implement more threads - its very simple ( memory management, etc not handled to have simple example )

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QThread>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QThread *thread1 = new QThread; // First thread
    QThread *thread2 = new QThread; // Second thread

    thread1->start();
    thread2->start(); 

    MyClass *myClass = new MyClass(false, "normal class");
    MyClass *mySleepClass = new MyClass(true, "sleeper class");

    // Better to implement start slot to start timer ( not implemented )
    // connect(thread1, SIGNAL(started), myClass, SLOT(start()));
    // but this suffice, because timer will emit first signal after class is moved to another thred
    //mySleepClass->moveToThread(thread1);
    //myClass->moveToThread(thread1);
}

MainWindow::~MainWindow()
{
    delete ui;
}

Now we can play with threads:

Blocking GUI ( of course we do not want this )

Initial example works without using new threads. Objects are in current thread and that's why GUI will be blocked. ( since I use sleep function in one instance )

//mySleepClass->moveToThread(thread1);
//myClass->moveToThread(thread1);

Non blocking GUI

We have two more threads running. Why not to use them. In example QThreads are already running, but they play with nothing. Let's move our instances there, to ensure main loop, where GUI is living will not be blocked anymore.

Magic function is moveToThread

Uncomment lines and you can see, that GUI will not be blocked. Both instances are in new thread. But then again, there is a sleep function so One should be counting faster then other. But it is not. Because they are blocking each other. They are in one thread.

mySleepClass->moveToThread(thread1);
myClass->moveToThread(thread1);

Results in both previous cases should be: ( instances lives in same thread and shares the same event loop, so they are blocking each other )

"normal class"  count:  1 
"sleeper class"  count:  1 
"normal class"  count:  2 
"sleeper class"  count:  2 
"normal class"  count:  3 
"sleeper class"  count:  3 

So move them to separate thread

Now GUI is not blocked, niether instances each other.

mySleepClass->moveToThread(thread1);
myClass->moveToThread(thread2);

Results should be: ( and GUI should not be blocked )

"sleeper class"  count:  1 
"normal class"  count:  1 
"normal class"  count:  2 
"normal class"  count:  3 
"normal class"  count:  4 
"normal class"  count:  5 

Hope It was understandable. As for me, this is more logic aproach then subclassing.

Of course you can create QThread in your MyClass, it is not necessary to create it oustide MyClass, I just wanted to show, that you can create one thread and move there more instances.

For anyone who disagree, I just wanted to say that: MyClass is counter with thread support sounds better then: MyClass is thread with counter ability :)