Starting QTimer In A QThread

46,268

Solution 1

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...

Solution 2

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();

Solution 3

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.

Solution 4

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().

Solution 5

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);
}
Share:
46,268
Tudor Pascu
Author by

Tudor Pascu

Updated on April 24, 2020

Comments

  • Tudor Pascu
    Tudor Pascu about 4 years

    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";
        }
    
  • Tudor Pascu
    Tudor Pascu about 12 years
    I've tried adding the exec() in the run method but I get QEventLoop: Cannot be used without QApplication.
  • jichi
    jichi about 11 years
    How can I start this timer outside somethread (in current thread)? Do I have to use QueuedConnection?
  • UmNyobe
    UmNyobe about 11 years
    connect a signal to the timer slot start() and trigger the signal
  • rbaleksandar
    rbaleksandar over 8 years
    Namely connect(somethread, SIGNAL(started()), timer, SLOT(start()))
  • Andreas Haferburg
    Andreas Haferburg about 7 years
    @Stormenet Some object with a slot doIt() that is supposed to be doing the work (in the created thread) whenever the timer fires.
  • SebiSebi
    SebiSebi about 7 years
    If I want to stop the thread and the timer is it safe to call thread.quit() and after that thread.wait()? Does "somethread" free the memory for the QTimer object?
  • UmNyobe
    UmNyobe about 7 years
    no, the thread does free anything. The rule of Qobject without parent apply, which means you have to delete at some point after thread.wait(). Note that timer doesnt have to be a pointer, can be a object directly (and a member of the caller) or shared pointed to.
  • pixelgrease
    pixelgrease over 5 years
    @rbaleksandar The function pointer syntax needs a cast in order to compile without errors: connect(somethread, &QThread::started, timer, static_cast<void (QTimer::*)()>(&QTimer::start));
  • rbaleksandar
    rbaleksandar over 5 years
    The cast is needed only when you use functor-based syntax for the slot-signal connection. With string-based connection that's not the case. Check this article if you are interested in the differences between the two syntax styles.