Qt timers cannot be stopped from another thread
Solution 1
Use QTimer
for this purpose and make use of SIGNALS
and SLOT
for the purpose of starting and stopping the timer/s from different threads. You can emit the signal from any thread and catch it in the thread which created the timer to act on it.
Since you say you are new to Qt, I suggest you go through some tutorials before proceeding so that you will know what Qt has to offer and don't end up trying to reinvent the wheel. :)
VoidRealms is a good starting point.
Solution 2
You have this problem because the timers in the static array is created in Thread X
, but started and stopped in Thread Y
. This is not allowed, because Qt rely on thread affinity to timeout timers.
You can either create, start stop in the same thread or use signal and slots to trigger start
and stop
operations for timers. The signal and slot solution is a bit problematic Because you have n
QTimer objects (Hint: how do you start the timer at position i
?)
What you can do instead is create and initialize the timer at position tmrnbr
in
TimerForFWUpgrade::set(unsigned char tmrnbr, unsigned int time)
{
singleTimer[tmrnbr] = new SingleTimer(0);
singleTimer[tmrnbr]->set(time);
}
which is executed by the same thread.
Futhermore, you don't need a SingleTimer
class. You are using Qt5, and you already have all you need at your disposal:
-
SingleTimer::isElapsed
is reallyQTimer::remainingTime() == 0
; -
SingleTimer::set
is reallyQTimer::setSingleShot(true); QTimer::start(time);
-
SingleTimer::slot_setElapsed
becomes useless - Thus
SingleTimer::SingleTimer
becomes useless and you dont need aSingleTimer
class anymore
Related videos on Youtube
Matt
Updated on July 11, 2020Comments
-
Matt almost 4 years
Hy,
I'm writing my first Qt program and getting now in troubles with:
QObject::killTimer: timers cannot be stopped from another thread
QObject::startTimer: timers cannot be started from another thread
My program will communicate to a CANOpen bus for that I'm using the Canfestival Stack. The Canfestival will work with callback methods. To detects timeout in communication I setup a timer function (somehow like a watchdog). My timer package consist out of a "tmr" module, a "TimerForFWUpgrade" module and a "SingleTimer" module. The "tmr" module was originally C programmed so the static "TimerForFWUpgrade" methods will interface it. The "tmr" module will be part of a C programed Firmware update package.
The timer will work as follows. Before a message is sent I will call TMR_Set method. An then in my idle program loop with TMR_IsElapsed we check for a timer underflow. If TMR_IsElapsed I will do the errorhandling. As you see the TMR_Set method will be called continuously and restart the QTimer again and again.
The above noted errors are appearing if I start my program. Can you tell me if my concept could work? Why does this errors appear? Do I have to use additional threads (QThread) to the main thread?
Thank you
Matt
Run and Idle loop:
void run { // start communicate with callbacks where TMR_Set is set continously ... while(TMR_IsElapsed(TMR_NBR_CFU) != 1); // if TMR_IsElapsed check for errorhandling .... }
Module tmr (interface to C program):
extern "C" { void TMR_Set(UINT8 tmrnbr, UINT32 time) { TimerForFWUpgrade::set(tmrnbr, time); } INT8 TMR_IsElapsed(UINT8 tmrnbr) { return TimerForFWUpgrade::isElapsed(tmrnbr); } }
Module TimerForFWUpgrade:
SingleTimer* TimerForFWUpgrade::singleTimer[NR_OF_TIMERS]; TimerForFWUpgrade::TimerForFWUpgrade(QObject* parent) { for(unsigned char i = 0; i < NR_OF_TIMERS; i++) { singleTimer[i] = new SingleTimer(parent); } } //static void TimerForFWUpgrade::set(unsigned char tmrnbr, unsigned int time) { if(tmrnbr < NR_OF_TIMERS) { time *= TimerForFWUpgrade::timeBase; singleTimer[tmrnbr]->set(time); } } //static char TimerForFWUpgrade::isElapsed(unsigned char tmrnbr) { if(true == singleTimer[tmrnbr]->isElapsed()) { return 1; } else { return 0; } }
Module SingleTimer:
SingleTimer::SingleTimer(QObject* parent) : QObject(parent), pTime(new QTimer(this)), myElapsed(true) { connect(pTime, SIGNAL(timeout()), this, SLOT(slot_setElapsed())); pTime->setTimerType(Qt::PreciseTimer); pTime->setSingleShot(true); } void SingleTimer::set(unsigned int time) { myElapsed = false; pTime->start(time); } bool SingleTimer::isElapsed() { QCoreApplication::processEvents(); return myElapsed; } void SingleTimer::slot_setElapsed() { myElapsed = true; }
-
Dmitry Sazonov over 9 yearsYou have great overhead. Why you don't use
QTimer
class?
-