简体   繁体   中英

QTimer not firing in a thread

I have an Qt5 c++ app with 2 threads, thread A is started when the main program starts up. The start method of thread A runs successfully.

So far so good. Next, in the main program I send a signal to Thread A to start a QTimer, which it does - but that timer never expires!

Thread B handles tcp connections. When I initiate a telnet connection to my app, thread B fires up and suddenly I see my Qtimer from thread A expiring at normal intervals.

Why is the QTimer from thread A not expiring until thread B starts?

I suspect my threads are getting messed up. note the last section of code below products this:

thread of this:  QThread(0x200fe00)  
thread of timer:  QThread(0x1fff470)

Which suggest my worker object (this), is in a different thread from my timer object. This timer thread address is actually the MAIN thread. Why? I'm confused.

Suggestions?


In my main app I create and start my thread like this:

QThread * MyControllerThread = new QThread(this);

if (MyControllerThread) {

    TheController *worker = new TheController(MyControllerThread);

    if (worker) {
        connect(MyControllerThread, SIGNAL(started()), worker, SLOT(start()));
        connect(MyControllerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
        connect(MyControllerThread, SIGNAL(finished()), MyControllerThread, SLOT(deleteLater()));
        worker->moveToThread(MyControllerThread);  
        MyControllerThread->start();  
    } 

and in my main app I emit a signal to the new thread:

    emit sig_startlocalpeer(Types::EActionLocalServiceStart);  // Move the local peer to standby mode to start remote tests

which runs a slot in my thread (TheController object):

connect(&m_remotetestintervaltimer,SIGNAL(timeout()),this,SLOT(expiredRemoteTestIntervalTimer()));
m_remotetestintervaltimer.setTimerType(Qt::VeryCoarseTimer);
m_remotetestintervaltimer.start(REMOTETEST_TIMER_INTERVAL);  // Wait between ticks
qDebug() << "thread of this: " << this->thread();
qDebug() << "thread of timer: " << m_remotetestintervaltimer.thread();

Well, it's not a Qt5 bug, it's more an inaccurate understanding of Qt's thread spirit.

In Qt, you have two ways to implement a thread which are using or not an even loop. Here is just a small visual example.

No event loop

myMethodCalledInANewThread
{
    do{ ... }while(...);
}

With an event loop

myMethodCalledInANewThread
{
    [...]
    exec();
}

(Of course you can mix a do/while with an even loop but stay simple).

In QTimer's doc, you can read:

In multithreaded applications, you can use QTimer in any thread that has an event loop. [...] 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.

So i'm pretty sure you don't have a second event loop in your second thread and that's why you have the behaviour you described.

To give you some tips to be totally clear with thread using Qt, I suggest you to read:

and a very good article about how QThread implementation is misunderstandood by a lot of user. - You're doing it wrong: http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/

I hope it will help ;)

The best answer seems to be a combination of RobbieE and Kuba:

You have to explicitly set the parent of the member variable in constructor. The parent-child feature is a Qt thing that exists among classes derived from QObject, it is not a feature of C++.

I never knew this - I assumed that when an object was created, its members variables automatically had their parent set to the object. Good to know!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM