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]


  • Qt Champions 2016

    @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...


  • Qt Champions 2016

    @Oleg_Suf

    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.



  • @Oleg_Suf ,

    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:

    @Oleg_Suf ,

    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))


  • Qt Champions 2016

    @Oleg_Suf
    You could wait some ticks before stopping

    ala 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++;
    }


  • Qt Champions 2016

    @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.


  • Lifetime Qt Champion

    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


  • Qt Champions 2016

    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


  • Lifetime Qt Champion

    What order is that ?

    Are you also ensuring that the hardware sends its data always at the same pace and in the same order ?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.