Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Starting QTimer In A QThread

I am trying to start a QTimer in a specific thread. However, the timer does not seem to execute and nothing is printing out. Is it something to do with the timer, the slot or the thread?

main.cpp

    #include "MyThread.h"
    #include <iostream>
    using namespace std;

    int main(int argc, char *argv[]) {
        MyThread t;
        t.start();
        while(1);
    }

MyThread.h

    #ifndef MYTHREAD_H
    #define MYTHREAD_H

    #include <QTimer>
    #include <QThread>
    #include <iostream>

    class MyThread : public QThread {
        Q_OBJECT
    public:
        MyThread();
    public slots:
        void doIt();
    protected:
        void run();
    };

    #endif  /* MYTHREAD_H */

MyThread.cpp

    #include "MyThread.h"

    using namespace std;

    MyThread::MyThread() {
        moveToThread(this);
    }

    void MyThread::run() {
        QTimer* timer = new QTimer(this);
        timer->setInterval(1);
        timer->connect(timer, SIGNAL(timeout()), this, SLOT(doIt()));
        timer->start();
    }

    void MyThread::doIt(){
        cout << "it works";
    }
like image 316
Tudor Pascu Avatar asked May 08 '12 04:05

Tudor Pascu


People also ask

How is QTimer implemented?

For QTimer to work, you must have an event loop in your application; that is, you must call QCoreApplication::exec() somewhere. Timer events will be delivered only while the event loop is running. In multithreaded applications, you can use QTimer in any thread that has an event loop.

What does QTimer singleShot do?

singleShot (int msec, QObject receiver, SLOT()SLOT() member) This static function calls a slot after a given time interval. It is very convenient to use this function because you do not need to bother with a timerEvent or create a local QTimer object.


5 Answers

As I commented (further information in the link) you are doing it wrong :

  1. You are mixing the object holding thread data with another object (responsible of doIt()). They should be separated.
  2. There is no need to subclass QThread in your case. Worse, you are overriding the run method without any consideration of what it was doing.

This portion of code should be enough

QThread* somethread = new QThread(this);
QTimer* timer = new QTimer(0); //parent must be null
timer->setInterval(1);
timer->moveToThread(somethread);
//connect what you want
somethread->start();

Now (Qt version >= 4.7) by default QThread starts a event loop in his run() method. In order to run inside a thread, you just need to move the object. Read the doc...

like image 178
UmNyobe Avatar answered Oct 27 '22 03:10

UmNyobe


m_thread = new QThread(this);
QTimer* timer = new QTimer(0); // _not_ this!
timer->setInterval(1);
timer->moveToThread(m_thread);
// Use a direct connection to whoever does the work in order
// to make sure that doIt() is called from m_thread.
worker->connect(timer, SIGNAL(timeout()), SLOT(doIt()), Qt::DirectConnection);
// Make sure the timer gets started from m_thread.
timer->connect(m_thread, SIGNAL(started()), SLOT(start()));
m_thread->start();
like image 39
Andreas Haferburg Avatar answered Oct 27 '22 01:10

Andreas Haferburg


A QTimer only works in a thread that has an event loop.

http://qt-project.org/doc/qt-4.8/QTimer.html

In multithreaded applications, you can use QTimer in any thread that has an event loop. To start an event loop from a non-GUI thread, use QThread::exec(). Qt uses the timer's thread affinity to determine which thread will emit the timeout() signal. Because of this, you must start and stop the timer in its thread; it is not possible to start a timer from another thread.

like image 40
Brian Roach Avatar answered Oct 27 '22 01:10

Brian Roach


You can use the emit signal and start the timer inside the emitted slot function

main.cpp

#include "MyThread.h"
#include <iostream>
using namespace std;

int main(int argc, char *argv[]) {
    MyThread t;
    t.start();
    while(1);
}

MyThread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QTimer>
#include <QThread>
#include <iostream>

class MyThread : public QThread {
    Q_OBJECT
public:
    MyThread();
    QTimer *mTimer;
signals:
   start_timer();
public slots:
    void doIt();
    void slot_timer_start();
protected:
    void run();
};

#endif  /* MYTHREAD_H */

MyThread.cpp

#include "MyThread.h"

using namespace std;

MyThread::MyThread() {
    mTimer = new QTimer(this);
    connect(this,SIGNAL(start_timer()),this, SLOT(slot_timer_start()));
    connect(mTimer,SIGNAL(timeout()),this,SLOT(doIt()));

}

void MyThread::run() {
    emit(start_timer());
    exec();
}

void MyThread::doIt(){
    cout << "it works";
}
void MyThread::slot_timer_start(){
    mTimer->start(1000);
}
like image 30
pathaleswar Avatar answered Oct 27 '22 02:10

pathaleswar


You need an event loop to have timers. Here's how I solved the same problem with my code:

MyThread::MyThread() {
}

void MyThread::run() {
    QTimer* timer = new QTimer(this);
    timer->setInterval(1);
    timer->connect(timer, SIGNAL(timeout()), this, SLOT(doIt()));
    timer->start();

    /* Here: */
    exec();             // Starts Qt event loop and stays there
   // Which means you can't have a while(true) loop inside doIt()
   // which instead will get called every 1 ms by your init code above.
}

void MyThread::doIt(){
    cout << "it works";
}

Here's the relevant piece of the documentation that none of the other posters mentioned:

int QCoreApplication::exec()

Enters the main event loop and waits until exit() is called. Returns the value that was set to exit() (which is 0 if exit() is called via quit()). It is necessary to call this function to start event handling. The main event loop receives events from the window system and dispatches these to the application widgets. To make your application perform idle processing (i.e. executing a special function whenever there are no pending events), use a QTimer with 0 timeout. More advanced idle processing schemes can be achieved using processEvents().

like image 29
PurpleHaze Avatar answered Oct 27 '22 02:10

PurpleHaze