Solved A problem with single slot connected to multiple signals
-
Hello! Can't figure out what the problem is in my project with single slot connected to several signals.
Seems like the execution sequence of code lines is broken.My GUI app has, let's say, three signals, which are connected to one slot. The signals are emitted
very fast, and slot fulfillment takes a bit of time. As you can see in example below, triggerings
of the slot begin in one sequence, and finish in completely different sequence. And I can't understand
how to fix it.
The sources of signals are single-shot timers, the troubling slot is "on_TimerTick()":--dialog.h--
{ private slots: void on_TimerTick(); void on_pushButton_clicked();//launching timers private: Ui::Dialog ui; void Print(QString message); QTimer* tmr1; QTimer* tmr2; QTimer* tmr3; void mySleep(int msec); }; //---dialog.cpp--- //constructor { tmr1 = new QTimer(this); tmr2 = new QTimer(this); tmr3 = new QTimer(this); tmr1->setObjectName("tmr1"); tmr2->setObjectName("tmr2"); tmr3->setObjectName("tmr3"); tmr1->setSingleShot(true); tmr2->setSingleShot(true); tmr3->setSingleShot(true); connect(tmr1, &QTimer::timeout, this, &Dialog::on_TimerTick); connect(tmr2, &QTimer::timeout, this, &Dialog::on_TimerTick); connect(tmr3, &QTimer::timeout, this, &Dialog::on_TimerTick); }
void Dialog::Print(QString message) { ui->textBrowser->append(message); } void Dialog::mySleep(int msec)//imitation of delay in slot's execution { QEventLoop loop; QTimer::singleShot(msec, &loop, SLOT(quit())); loop.exec(); } //The weird Slot void Dialog::on_TimerTick() { Print(QString("Started ") + QObject::sender()->objectName()); mySleep(2); Print(QString("Stopped ") + QObject::sender()->objectName()); } void Dialog::on_pushButton_clicked() { tmr1->start(1); tmr2->start(1); tmr3->start(1); }
Output:
Started tmr3 Started tmr1 Started tmr2 Stopped tmr2 Stopped tmr1 Stopped tmr3
I've tried to use overloaded versions of connect-method in constructor with fifth parameter:
Qt::QueuedConnection, but it didn't help. And if slot would be executed in different threads I'd probably
just put the QMutex to enforce the right sequence of slot executions, like:
//--What I want-example-Started tmr3 Started tmr1 Started tmr2 Stopped tmr3 Stopped tmr1 Stopped tmr2
//----------------------,
but all slot triggerings are performed in single (main) thread.Can anybody please explain how to fix the situation? Thanks
[Russian version: https://forum.qt.io/topic/81859/проблема-при-соединении-нескольких-сигналов-с-одним-слотом ~kshegunov]
-
@Oleg_Suf
Hi
If you remove mySleep(2); does it still come out of order ? -
@mrjj said in A problem with single slot connected to multiple signals:
@Oleg_Suf
Hi
If you remove mySleep(2); does it still come out of order ?If I remove mySleep(2) the order becomes correct. But in real task some PCs do have a certain latency, so I wish I could get rid of it in my work project, but...
-
Ok i was wondering the the local event loop would interfere with
the regular and it seems it does.If they perform heavy task in real world, you should rather
use threads as not to hang the main thread. -
Set some delay between the timers.
void Dialog::on_pushButton_clicked()
{
tmr1->start(1);
tmr2->start(2);
tmr3->start(3);
} -
@Vinod-Kuntoji said in A problem with single slot connected to multiple signals:
Set some delay between the timers.
I would love to do this, but it's just a model example, real app signals come from hardware, and I'm unable to affect its reaction time.
I guess I have two choises then - 1) Try to reduce the slot execution time by all means; 2) Perform every new task in separate thread and use mutex (I'd really wish to avoid that)) -
@Oleg_Suf
You could wait some ticks before stoppingala something like
(for testing)void Dialog::on_TimerTick()
{
static int tickcc=1;
if (tickcc == 1)
Print(QString("Started ") + QObject::sender()->objectName());
else if (tickcc > 4 ) {
Print(QString("Stopped ") + QObject::sender()->objectName());
tickcc =0;
}
tickcc++;
} -
@Oleg_Suf said in A problem with single slot connected to multiple signals:
And I can't understand
how to fix it.You can't reliably change that. A timer will fire the first opportunity it has (i.e. when control returns to the event loop) but there's no guarantee for ordering it depends on which timers have timed out at the time of check, and which haven't. In any case you should not depend on the order of appearance of signal emissions/slot calls.
-
Hi,
Can you explain how your application is supposed to react to these hardware "signals" ? And also why is it the same slot that is called for what seems to be different hardware ?
-
@SGaist said:
Can you explain how your application is supposed to react to these hardware "signals" ?
Hardware sends data, my program processes these packages of data in the same way every time, and every time responds;
And also why is it the same slot that is called for what seems to be different hardware ?
No, hardware is the same, it just triggers very fast
-
I don't follow, why would you need to ensure a specific order of the slot execution/signal emission then?
-
@kshegunov said:
I don't follow, why would you need to ensure a specific order of the slot execution/signal emission then?
Because order matters to user. Anyway, I concluded, that if I can't increase time interval between signals emittions, I have to decrease slot execution time, there is no other way to ensure consistency in this case. The given example is simplified, but in original task, I ended up performing data processing (which was shown as "mySleep(2);") in worker thread, and all GUI things (which were shown as Print() methods) - in main thread.
Thanks to everyone -
What order is that ?
Are you also ensuring that the hardware sends its data always at the same pace and in the same order ?