MoveToThread and QTimer



  • Hi,

    I cannot figure out how moveToThread is working with QTimer class member.

    I have a simple code example of my problem.

    Description of the code example:
    MyObject1:
    Create MyObject2.
    Move MyObject2 to a thread using moveToThread.
    Connect the started signal from QThread to the MyObject1 slot process.

    MyObject2:
    Class that inherits from QObject.
    Contain a QTimer member.
    Contain a process slot.

    Running behavior:
    In the process slot of MyObject2 I start my QTimer class member and I get:
    @QObject::startTimer: timers cannot be started from another thread@

    Resolve the problem:
    I can get rid of this, by defining my QTimer member as a pointer and create it in the process slot.

    Question:
    What I do not understand is why in the case that my QTimer class member is not a pointer, my timer is running in a different thread?
    moveToThread should make it running in the same thread as MyObject2 thread, no?

    Code example:
    @#include <QDebug>
    #include <QThread>

    #include "mythread1.h"
    #include "mythread2.h"

    MyObject1::MyObject1(QObject *parent) :
    QObject(parent)
    {
    qDebug() << "Constructor object1, THREAD :" << QThread::currentThreadId();

     m_object2 = new MyObject2();
     QThread *thread1 = new QThread();
     m_object2->moveToThread(thread1);
     connect (thread1, SIGNAL(started()), m_object2, SLOT(process()));
     thread1->start();
    

    }

    #ifndef MYTHREAD1_H
    #define MYTHREAD1_H

    #include "mythread2.h"

    class MyObject1 : public QObject
    {
    Q_OBJECT
    public:
    explicit MyObject1(QObject *parent = 0);

    MyObject2 *m_object2;
    

    signals:
    public slots:
    protected:
    private:
    };

    #endif // MYTHREAD1_H

    #include <QDebug>
    #include <QThread>
    #include "mythread2.h"

    MyObject2::MyObject2(QObject *parent) :
    QObject(parent)
    {
    qDebug() << "Constructor object2, THREAD :" << QThread::currentThreadId();
    }

    void MyObject2::process()
    {
    qDebug() << "Object2" << func << "THREAD :" << QThread::currentThreadId();
    m_timer.setInterval(5000);
    connect (&m_timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
    m_timer.start();
    }

    void MyObject2::onTimeout()
    {
    qDebug() << func << "Object2 THREAD :" << QThread::currentThreadId();
    }

    #ifndef MYTHREAD2_H
    #define MYTHREAD2_H

    #include <QTimer>

    class MyObject2 : public QObject
    {
    Q_OBJECT
    public:
    explicit MyObject2(QObject *parent = 0);

    QTimer m_timer;
    

    signals:

    public slots:
    void process(void);
    void onTimeout(void);

    protected:

    };

    #endif // MYTHREAD2_H@

    Thanks in advance for your help.

    Julien.



  • Hi, I've not checked directly, but the timer is not a child of MyObject2 thus is not moved to the new thread.



  • [quote author="tlvju" date="1350384177"]
    moveToThread should make it running in the same thread as MyObject2 thread, no?
    [/quote]

    I have the same question. Why m_timer isn't moved to another thread?



  • m_timer is not parented to anything, thus it is not moved to the thread.



  • Be aware that just because m_timer is a member of a QObject-based class, it does not automatically become a child of it and thus, as luca already pointed out, it is not moved to the new thread.

    You either move it explicitly or set the surrouding class as the parent to get it moved implicitly.



  • Thanks luca, you've answered about our question above but I didn't read it. Sorry.

    I tried:

    1. Add new member variables to MyObject2 (QTimer* m_timer2, m_timer3).
    2. Add this code under line 55 (MyObject2::process()).
      @m_timer2 = new QTimer();
      m_timer3 = new QTimer(this);
      qDebug() << "Parent of m_timer is" << m_timer.parent();
      qDebug() << "Parent of m_timer2 is" << m_timer2->parent();
      qDebug() << "Parent of m_timer3 is" << m_timer3->parent();@

    Application output:
    @Constructor object1, THREAD : 3055531792
    Constructor object2, THREAD : 3055531792
    Object2 process THREAD : 3019897712
    Parent of m_timer is QObject(0x0)
    Parent of m_timer2 is QObject(0x0)
    Parent of m_timer3 is MyObject2(0x9563f20)
    ...@

    (Parent of m_timer and m_timer2 is QObject in my case)

    BANG! I got it.
    Thank you very much.

    Kay



  • Thank you Lukas!
    I 'm newbie and I didn't know that:
    [quote author="Lukas Geyer" date="1350451175"]m_timer is a member of a QObject-based class, it does not automatically become a child of it [/quote]

    Kay



  • I understand now that my m_timer object class member is not a child of my object.

    But I still do not understand something.
    I have done what Kay tried, so having three timers created in three different ways and qDebug the parent of those timers.

    You can see that m_timer2 has the same parent as m_timer but:
    m_timer.start() is nok :
    @QObject::startTimer: timers cannot be started from another thread@

    m_timer2->start() is ok:
    signal/slot are working



  • Yes, m_timer and m_timer2 have the same parent, 0x0 or 0 or NULL or nullptr, which means that both have no parent. So m_timer is not moved to thread1.



  • bq. Yes, m_timer and m_timer2 have the same parent, 0×0, which means that both have no parent.

    Then why m_timer2 is able to be started from the thread and m_timer not?
    I expect that m_timer2 is also not able to be started.
    Is it because a new is done in the function process so in the thread, and then m_timer2 is really living in the thread since created in it?



  • Because m_timer2 has been created after m_object2 has been moved to thread1, whereas m_timer is created before. The code in process() is executed in thread1, not the main thread.

    An object always 'lives' in the thread it has been created (until moved to another thread of course).



  • Ok great, thanks a lot for your answers, that's now completely clear :-).


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.