QTimer does not fire slot
-
I have a QTimer * I allocate in a function running in a thread.
In the same function, I connect its timeout signal to a slot, then I set it as a single shot timer and start it.
Next, I call another function and sleep for a while waiting for the timer to expire and call the slot. The timer expires but the slot never gets called, by the way if a I call QCoreApplication::processEvents(); after the sleep time the slot gets called.
I do not understand this behavior and I do not know how obviate to this problem without calling the processEventsThank you in advance
-
@ulix
Show your code. You may have a threading issue. Qt timers only cause timeout signal to call slot if event loop is running. Don't know what your "sleep" is, likely to block the event loop? E.g. if you callsleep()
that is not going to get interrupted by aQTimer
timeout. -
@JonB The code is:
void FWCommissioningTask::runTask() { ... if (!GetGwMgr->executeFirmwareCommissioning(identifier, commissioning.path, end_points)) { ... } _task_mutex.lock(); _task_condition.wait(&_task_mutex); return; } bool GWMgr::executeFirmwareCommissioning(QString identifier, QString commissioningPath, QList<QString> endPoints) { return mOTAUpdateMgr.executeFirmwareCommissioning(identifier, commissioningPath, endPoints); } bool OTAUpdateMgr::executeFirmwareCommissioning(QString id, QString fwPath, QList<QString> MACs) { ... _evaluate_fsm_state_actions(OTAUpdateFSMState::commissioning); return true; } void OTAUpdateMgr::_evaluate_fsm_state_actions(const OTAUpdateFSMState state) { switch (state) { ... case OTAUpdateFSMState::commissioning: _init_commissioning_phase(); _launch_commissioning_phase(); break; case OTAUpdateFSMState::confirmed: if (_init_confirmed_state()) { _launch_confirmed_actions(); } else { _evaluate_fsm_state_actions(OTAUpdateFSMState::error); } break; ... } } bool OTAUpdateMgr::_init_commissioning_phase() { ... return true; } bool OTAUpdateMgr::_launch_commissioning_phase() { if (_first_message_timer == nullptr) { _first_message_timer = new QTimer(); } for(auto nodeData: m_FSM.nodes) { ... if (!_first_message_timer->isActive()) { connect(_first_message_timer, &QTimer::timeout, this, &OTAUpdateMgr::_on_first_message_espiration); _first_message_timer->setSingleShot(true); ... _first_message_timer->start(sleep_time); } } _evaluate_fsm_state_actions(OTAUpdateFSMState::confirmed); return true; } void OTAUpdateMgr::_on_first_message_espiration() { ... }
Notice the
runTask
is the entry point of a thread where all starts -
@ulix
Are you expecting the single shot timer to timeout whilerunTask()
is waiting on_task_condition.wait(&_task_mutex);
? It won't.Separately: since you go
new QTimer()
without passingthis
as parent does your destructor deletethis->_first_message_timer
? Or it seems to me simpler to put theQTimer
as a member variable without the pointer/new
so it does not need freeing. -
@ulix
You have aQTimer
in a thread which does not run the Qt event loop, does it? So no signals will be delivered. Hence your finding:The timer expires but the slot never gets called, by the way if a I call QCoreApplication::processEvents(); after the sleep time the slot gets called.
That
processEvents()
is the first time the evet loop is invoked. Your thread needs to be running the event loop all the time if that's where the timer is ticking (unless you move the timer to the main UI thread). SeeQThread::run()
&QThread::exec()
.