The timeout slot is not fired when the timer is called from a separate thread in the main()
-
Hi there,
I have the following code
#include <QtConcurrent/QtConcurrent> #include <QApplication> #include <QDateTime> #include <QDebug> #include <QObject> #include <QTimer> class PrintThreadIdTimer : public QObject { Q_OBJECT public: PrintThreadIdTimer(int interval, QObject *parent = nullptr) { m_timer = new QTimer(this); m_timer->setInterval(interval); connect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); } ~PrintThreadIdTimer() { disconnect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); delete m_timer; m_timer = nullptr; } void start() { m_timer->start(); } void stop() { m_timer->stop(); } int interval() { return m_timer->interval(); } public slots: void printThreadIdAndTimeMsecs() { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "TimeMsecs:" << QDateTime::currentMSecsSinceEpoch(); } private: QTimer *m_timer = nullptr; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); qDebug() << Q_FUNC_INFO << "Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); auto appRunAndExit = [=]() { // Just wait a little bit to enter the event loop QThread::msleep(1000); PrintThreadIdTimer *printThreadTimer = new PrintThreadIdTimer(1000); printThreadTimer->start(); for (int i = 0; i < 3; ++i) { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "interval():" << printThreadTimer->interval() << "Time:" << QDateTime::currentMSecsSinceEpoch(); QThread::msleep(1000); } printThreadTimer->stop(); QCoreApplication::quit(); }; QThreadPool::globalInstance()->start(appRunAndExit); qDebug() << Q_FUNC_INFO << "-> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); int out = app.exec(); qDebug() << Q_FUNC_INFO << "---> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); return out; } #include "cpp-qt6-threaded-timers.moc"
The class
PrintThreadIdTimer
is just a wrapper class on aQTimer
which is calling theprintThreadIdAndTimeMsecs
when the timeout signal is sent.Now I wanted to use this class on a simple application, but as far as I know, the
QTimer
needs an event loop, so I used theQApplication::exec()
.I used the lambda function
appRunAndExit ()
in order to create a simple example where I am using thePrintThreadIdTimer
and then closing the application. I run this function on a separate thread usingQThreadPool::globalInstance()->start()
.Now, when I run the above example, it seems that the slot function is not called, and I am not really sure why. The output that I am getting is the following
int main(int, char**) Thread: 0x7f420c7ca880 Time: 1700741341051 int main(int, char**) -> Thread: 0x7f420c7ca880 Time: 1700741341052 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741342052 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741343053 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741344054 int main(int, char**) ---> Thread: 0x7f420c7ca880 Time: 1700741345055
What is the issue in the above code? Do I need to change something, or have I understood something wrong?
I am using Qt 6.2.5.
Let me know if you need more information.
Kind regards,
Stavros
-
Hi there,
I have the following code
#include <QtConcurrent/QtConcurrent> #include <QApplication> #include <QDateTime> #include <QDebug> #include <QObject> #include <QTimer> class PrintThreadIdTimer : public QObject { Q_OBJECT public: PrintThreadIdTimer(int interval, QObject *parent = nullptr) { m_timer = new QTimer(this); m_timer->setInterval(interval); connect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); } ~PrintThreadIdTimer() { disconnect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); delete m_timer; m_timer = nullptr; } void start() { m_timer->start(); } void stop() { m_timer->stop(); } int interval() { return m_timer->interval(); } public slots: void printThreadIdAndTimeMsecs() { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "TimeMsecs:" << QDateTime::currentMSecsSinceEpoch(); } private: QTimer *m_timer = nullptr; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); qDebug() << Q_FUNC_INFO << "Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); auto appRunAndExit = [=]() { // Just wait a little bit to enter the event loop QThread::msleep(1000); PrintThreadIdTimer *printThreadTimer = new PrintThreadIdTimer(1000); printThreadTimer->start(); for (int i = 0; i < 3; ++i) { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "interval():" << printThreadTimer->interval() << "Time:" << QDateTime::currentMSecsSinceEpoch(); QThread::msleep(1000); } printThreadTimer->stop(); QCoreApplication::quit(); }; QThreadPool::globalInstance()->start(appRunAndExit); qDebug() << Q_FUNC_INFO << "-> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); int out = app.exec(); qDebug() << Q_FUNC_INFO << "---> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); return out; } #include "cpp-qt6-threaded-timers.moc"
The class
PrintThreadIdTimer
is just a wrapper class on aQTimer
which is calling theprintThreadIdAndTimeMsecs
when the timeout signal is sent.Now I wanted to use this class on a simple application, but as far as I know, the
QTimer
needs an event loop, so I used theQApplication::exec()
.I used the lambda function
appRunAndExit ()
in order to create a simple example where I am using thePrintThreadIdTimer
and then closing the application. I run this function on a separate thread usingQThreadPool::globalInstance()->start()
.Now, when I run the above example, it seems that the slot function is not called, and I am not really sure why. The output that I am getting is the following
int main(int, char**) Thread: 0x7f420c7ca880 Time: 1700741341051 int main(int, char**) -> Thread: 0x7f420c7ca880 Time: 1700741341052 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741342052 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741343053 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741344054 int main(int, char**) ---> Thread: 0x7f420c7ca880 Time: 1700741345055
What is the issue in the above code? Do I need to change something, or have I understood something wrong?
I am using Qt 6.2.5.
Let me know if you need more information.
Kind regards,
Stavros
@Stavros-Vaionitis
@jsulm knows better than I. It's not a good idea to do sleepy stuff, but I'm not sure that would be the issue here if the timer never runs.Your thread needs to run a Qt event loop (itself, not just the one in the main thread) for timers to work. I'm not sure your lambda runnable does this (from
QRunnable::run()
).QThread::run()
does. Perhaps @jsulm or someone would comment on whether this is correct/the issue? -
Hi there,
I have the following code
#include <QtConcurrent/QtConcurrent> #include <QApplication> #include <QDateTime> #include <QDebug> #include <QObject> #include <QTimer> class PrintThreadIdTimer : public QObject { Q_OBJECT public: PrintThreadIdTimer(int interval, QObject *parent = nullptr) { m_timer = new QTimer(this); m_timer->setInterval(interval); connect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); } ~PrintThreadIdTimer() { disconnect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); delete m_timer; m_timer = nullptr; } void start() { m_timer->start(); } void stop() { m_timer->stop(); } int interval() { return m_timer->interval(); } public slots: void printThreadIdAndTimeMsecs() { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "TimeMsecs:" << QDateTime::currentMSecsSinceEpoch(); } private: QTimer *m_timer = nullptr; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); qDebug() << Q_FUNC_INFO << "Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); auto appRunAndExit = [=]() { // Just wait a little bit to enter the event loop QThread::msleep(1000); PrintThreadIdTimer *printThreadTimer = new PrintThreadIdTimer(1000); printThreadTimer->start(); for (int i = 0; i < 3; ++i) { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "interval():" << printThreadTimer->interval() << "Time:" << QDateTime::currentMSecsSinceEpoch(); QThread::msleep(1000); } printThreadTimer->stop(); QCoreApplication::quit(); }; QThreadPool::globalInstance()->start(appRunAndExit); qDebug() << Q_FUNC_INFO << "-> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); int out = app.exec(); qDebug() << Q_FUNC_INFO << "---> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); return out; } #include "cpp-qt6-threaded-timers.moc"
The class
PrintThreadIdTimer
is just a wrapper class on aQTimer
which is calling theprintThreadIdAndTimeMsecs
when the timeout signal is sent.Now I wanted to use this class on a simple application, but as far as I know, the
QTimer
needs an event loop, so I used theQApplication::exec()
.I used the lambda function
appRunAndExit ()
in order to create a simple example where I am using thePrintThreadIdTimer
and then closing the application. I run this function on a separate thread usingQThreadPool::globalInstance()->start()
.Now, when I run the above example, it seems that the slot function is not called, and I am not really sure why. The output that I am getting is the following
int main(int, char**) Thread: 0x7f420c7ca880 Time: 1700741341051 int main(int, char**) -> Thread: 0x7f420c7ca880 Time: 1700741341052 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741342052 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741343053 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741344054 int main(int, char**) ---> Thread: 0x7f420c7ca880 Time: 1700741345055
What is the issue in the above code? Do I need to change something, or have I understood something wrong?
I am using Qt 6.2.5.
Let me know if you need more information.
Kind regards,
Stavros
@Stavros-Vaionitis said in The timeout slot is not fired when the timer is called from a separate thread in the main():
What is the issue in the above code?
The for loop with QThread::msleep(1000) - don't do such things in event driven applications.
-
Hi there,
I have the following code
#include <QtConcurrent/QtConcurrent> #include <QApplication> #include <QDateTime> #include <QDebug> #include <QObject> #include <QTimer> class PrintThreadIdTimer : public QObject { Q_OBJECT public: PrintThreadIdTimer(int interval, QObject *parent = nullptr) { m_timer = new QTimer(this); m_timer->setInterval(interval); connect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); } ~PrintThreadIdTimer() { disconnect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); delete m_timer; m_timer = nullptr; } void start() { m_timer->start(); } void stop() { m_timer->stop(); } int interval() { return m_timer->interval(); } public slots: void printThreadIdAndTimeMsecs() { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "TimeMsecs:" << QDateTime::currentMSecsSinceEpoch(); } private: QTimer *m_timer = nullptr; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); qDebug() << Q_FUNC_INFO << "Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); auto appRunAndExit = [=]() { // Just wait a little bit to enter the event loop QThread::msleep(1000); PrintThreadIdTimer *printThreadTimer = new PrintThreadIdTimer(1000); printThreadTimer->start(); for (int i = 0; i < 3; ++i) { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "interval():" << printThreadTimer->interval() << "Time:" << QDateTime::currentMSecsSinceEpoch(); QThread::msleep(1000); } printThreadTimer->stop(); QCoreApplication::quit(); }; QThreadPool::globalInstance()->start(appRunAndExit); qDebug() << Q_FUNC_INFO << "-> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); int out = app.exec(); qDebug() << Q_FUNC_INFO << "---> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); return out; } #include "cpp-qt6-threaded-timers.moc"
The class
PrintThreadIdTimer
is just a wrapper class on aQTimer
which is calling theprintThreadIdAndTimeMsecs
when the timeout signal is sent.Now I wanted to use this class on a simple application, but as far as I know, the
QTimer
needs an event loop, so I used theQApplication::exec()
.I used the lambda function
appRunAndExit ()
in order to create a simple example where I am using thePrintThreadIdTimer
and then closing the application. I run this function on a separate thread usingQThreadPool::globalInstance()->start()
.Now, when I run the above example, it seems that the slot function is not called, and I am not really sure why. The output that I am getting is the following
int main(int, char**) Thread: 0x7f420c7ca880 Time: 1700741341051 int main(int, char**) -> Thread: 0x7f420c7ca880 Time: 1700741341052 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741342052 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741343053 main(int, char**)::<lambda()> ThreadId: 0x7f4201f7a640 interval(): 1000 Time: 1700741344054 int main(int, char**) ---> Thread: 0x7f420c7ca880 Time: 1700741345055
What is the issue in the above code? Do I need to change something, or have I understood something wrong?
I am using Qt 6.2.5.
Let me know if you need more information.
Kind regards,
Stavros
@Stavros-Vaionitis
@jsulm knows better than I. It's not a good idea to do sleepy stuff, but I'm not sure that would be the issue here if the timer never runs.Your thread needs to run a Qt event loop (itself, not just the one in the main thread) for timers to work. I'm not sure your lambda runnable does this (from
QRunnable::run()
).QThread::run()
does. Perhaps @jsulm or someone would comment on whether this is correct/the issue? -
@Stavros-Vaionitis said in The timeout slot is not fired when the timer is called from a separate thread in the main():
What is the issue in the above code?
The for loop with QThread::msleep(1000) - don't do such things in event driven applications.
Hi @jsulm,
Thanks for your quick reply. I am aware about the sleep() and the for loop for event driven apps, but this is a quick and dirty example that I wanted to test
QTimer
with a simple example. -
Hi @jsulm,
Thanks for your quick reply. I am aware about the sleep() and the for loop for event driven apps, but this is a quick and dirty example that I wanted to test
QTimer
with a simple example.How should the timer send a signal when there is no eventloop running where it can be created?
-
How should the timer send a signal when there is no eventloop running where it can be created?
Hi @Christian-Ehrlicher and @JonB,
Thank you for your quick replies and the valuable input. I thought that the main event loop is accessible from all the threads that are created there. I modified my code as follows
#include <QtConcurrent/QtConcurrent> #include <QApplication> #include <QDateTime> #include <QDebug> #include <QMetaObject> #include <QObject> #include <QTimer> class PrintThreadIdTimer : public QObject { Q_OBJECT public: PrintThreadIdTimer(int interval, QObject *parent = nullptr) { m_timer = new QTimer(this); m_timer->setInterval(interval); connect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); } ~PrintThreadIdTimer() { disconnect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); delete m_timer; m_timer = nullptr; } int interval() { return m_timer->interval(); } public slots: void start() { m_timer->start(); } void stop() { m_timer->stop(); } private slots: void printThreadIdAndTimeMsecs() { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "TimeMsecs:" << QDateTime::currentMSecsSinceEpoch(); } private: QTimer *m_timer = nullptr; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); qDebug() << Q_FUNC_INFO << "Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); auto appRunAndExit = []() { PrintThreadIdTimer *printThreadTimer = new PrintThreadIdTimer(1000); QThread *thread = new QThread(); printThreadTimer->moveToThread(thread); QObject::connect(thread, &QThread::started, printThreadTimer, &PrintThreadIdTimer::start); QObject::connect(thread, &QThread::finished, printThreadTimer, &PrintThreadIdTimer::stop); thread->start(); for (int i = 0; i < 3; ++i) { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "interval():" << printThreadTimer->interval() << "Time:" << QDateTime::currentMSecsSinceEpoch(); QThread::msleep(1000); } thread->quit(); thread->wait(); QCoreApplication::quit(); }; QThreadPool::globalInstance()->start(appRunAndExit); qDebug() << Q_FUNC_INFO << "-> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); int out = app.exec(); qDebug() << Q_FUNC_INFO << "---> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); return out; }
Inside the lambda function I created another thread which I used it in order to move the
PrintThreadIdTimer
object there. I modified the classPrintThreadIdTimer
in order to havestart()
andstop()
slots to be connected with thestarted()
andfinished()
signals of the thread.Now, it's working as expected. I am not sure if there is a better way to do this.
Kind regards,
Stavros
-
Hi @Christian-Ehrlicher and @JonB,
Thank you for your quick replies and the valuable input. I thought that the main event loop is accessible from all the threads that are created there. I modified my code as follows
#include <QtConcurrent/QtConcurrent> #include <QApplication> #include <QDateTime> #include <QDebug> #include <QMetaObject> #include <QObject> #include <QTimer> class PrintThreadIdTimer : public QObject { Q_OBJECT public: PrintThreadIdTimer(int interval, QObject *parent = nullptr) { m_timer = new QTimer(this); m_timer->setInterval(interval); connect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); } ~PrintThreadIdTimer() { disconnect(m_timer, &QTimer::timeout, this, &PrintThreadIdTimer::printThreadIdAndTimeMsecs); delete m_timer; m_timer = nullptr; } int interval() { return m_timer->interval(); } public slots: void start() { m_timer->start(); } void stop() { m_timer->stop(); } private slots: void printThreadIdAndTimeMsecs() { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "TimeMsecs:" << QDateTime::currentMSecsSinceEpoch(); } private: QTimer *m_timer = nullptr; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); qDebug() << Q_FUNC_INFO << "Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); auto appRunAndExit = []() { PrintThreadIdTimer *printThreadTimer = new PrintThreadIdTimer(1000); QThread *thread = new QThread(); printThreadTimer->moveToThread(thread); QObject::connect(thread, &QThread::started, printThreadTimer, &PrintThreadIdTimer::start); QObject::connect(thread, &QThread::finished, printThreadTimer, &PrintThreadIdTimer::stop); thread->start(); for (int i = 0; i < 3; ++i) { qDebug() << Q_FUNC_INFO << "ThreadId:" << QThread::currentThreadId() << "interval():" << printThreadTimer->interval() << "Time:" << QDateTime::currentMSecsSinceEpoch(); QThread::msleep(1000); } thread->quit(); thread->wait(); QCoreApplication::quit(); }; QThreadPool::globalInstance()->start(appRunAndExit); qDebug() << Q_FUNC_INFO << "-> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); int out = app.exec(); qDebug() << Q_FUNC_INFO << "---> Thread:" << QThread::currentThreadId() << "Time:" << QDateTime::currentMSecsSinceEpoch(); return out; }
Inside the lambda function I created another thread which I used it in order to move the
PrintThreadIdTimer
object there. I modified the classPrintThreadIdTimer
in order to havestart()
andstop()
slots to be connected with thestarted()
andfinished()
signals of the thread.Now, it's working as expected. I am not sure if there is a better way to do this.
Kind regards,
Stavros
@Stavros-Vaionitis said in The timeout slot is not fired when the timer is called from a separate thread in the main():
I thought that the main event loop is accessible from all the threads th
Every thread has it's own event loop started inside QThread::run(): https://doc.qt.io/qt-6/qthread.html#details
And @JonB already told you this two posts above.
-