QTimer::singleShot(x00, [=]{ mysignal1; }); .... multiple time



  • As a post title use these lambda function for call 2-3 void each pushbutton toggle = true .... in more accurate description I create a qthread subbclass and after the user it have press a pushbutton on gui (toggled pushbutton) I call a void with a "series" of lambda functions.. so these signal it use for call the void on my qthread:

    mainwindows::myfunc(bool it)
    {
          if(it){
           QTimer::singleShot(100, [=]{ mysignal1; });
           QTimer::singleShot(300, [=]{ mysignal2; });
           QTimer::singleShot(500, [=]{ mysignal3; });
           QTimer::singleShot(700, [=]{ mysignal4; });
    
    }
    
    /* I use the mainwindows signal for call mythread void  ex:*/
    connect(this, SIGNAL(mysignal1(int)), myqthread, SLOT(mySigvoid(int)), Qt::Queuedconnection);
    ........
    .......
    /*in mythread....*/
    
    myqthread::run.....
    {
    /* .... mutex and off switch .... */
    do(;;)
    {
     switch(myvalue)
          case 1:
                 myvoid1();
                 break;
          case 2:
                 myvoid2();
                 break;
    
    ...../*etc etc...*/
    }
    }
    
    myqthread::myvoid1(){/*some stupid code called from signal1 from mainwindows...*/}
    myqthread::myvoid2(){/*some stupid code called from signal2 from mainwindows...*/}
    myqthread::myvoid3(){/*some stupid code called from signal3 from mainwindows...*/}
    myqthread::myvoid4(){/*some stupid code called from signal4 from mainwindows...*/}
    
    myqthread::mySigvoid(int theNewValue){
     if(theNewValue == thOldOne){}
    else {myvalue = theNewValue;}
    }
    

    sometime these "sequence" is not call .... these is related to bad use of these type of lambda function or the error is only on my /some stupid code/??

    regards
    giorgio



  • Hi, if you call your mythread void functions directly from your mainwindows signal; that means your're calling from one function to a function in another thread, and that's the reason I think why the call fails sometimes.



  • @gfxx Since Qt 5.2 a so called "context object" was added. When that object is destroyed, the connection is broken and the context is also used for the thread affinity.
    The lambda will be called in the thread of the event loop of the object used as context).

    From what I can see, you do not use such an context object in your lambda. That should make the thread where the Timer is created/started the thread that calls the function.
    That should be the reason why it sometimes works and sometimes it does not.



  • @J.Hilk In these case I must renew my code ...

    @hskoglund ... not understand your suggest: is not possible using signal/slot mechanism for call some function from mainwindows to qthread?
    Obviously I'm not a genius otherwise I would not need the forum .... But I need you to explain the concept better if you can. Is for me learning ... and sorry for my horrible English. Thank you.

    for more precision myqthread have a run function .... run function see my mainwindow signal and after it call myvoidx ... inside run function loop I have a big case switch statement that see the integer value of my signal ... so my signal is only integer value of the same variable....

    A better example of my mechanism...

    mainwindows::myfunc(bool it)
    {
          if(it){
           QTimer::singleShot(100, [=]{ mysignal1; });
           QTimer::singleShot(300, [=]{ mysignal2; });
           QTimer::singleShot(500, [=]{ mysignal3; });
           QTimer::singleShot(700, [=]{ mysignal4; });
    
    }
    
    /* I use the mainwindows signal for call mythread void  ex:*/
    connect(this, SIGNAL(mysignal1(int,int,bool)), myqthread, SLOT(mySigvoid(int,int,bool)), Qt::Queuedconnection);/*(int,int,bool) registerNumber, slaveStationNumber, on or off*/
    ........
    .......
    /*in mythread....*/
    
    int registernumber = 0;
    
    myqthread::run.....
    {
    /* .... mutex and off switch .... */
    do(;;)
    {
    if(myvalueIschangedTrue){
     switch(myvalue)
          case 1:
                  if(value){
                 myregisterwriting(slavestationnr, 1/*registernumber*/, 1/*registerValue = 1*/);}
                 else{myregisterwriting(slavestationnr, 1/*registernumber*/r, 0/*registerValue = 0*/);}
                 break;
          case 2:
                 myregisterwriting(slavestationnr, 2/*registernumber*/, 1/*registerValue = 1*/);}
                 else{myregisterwriting(slavestationnr, 2/*registernumber*/r, 0/*registerValue = 0*/);}
                 break;
    
    ...../*etc etc...*/
    }
    }
    }
    
    myqthread::myvoid1(){/*some stupid code called from signal1 from mainwindows...*/}
    myqthread::myvoid2(){/*some stupid code called from signal2 from mainwindows...*/}
    myqthread::myvoid3(){/*some stupid code called from signal3 from mainwindows...*/}
    myqthread::myvoid4(){/*some stupid code called from signal4 from mainwindows...*/}
    
    myqthread::mySigvoid(int theNewValue){
     if(theNewValue == thOldOne){}
    else {myvalue = theNewValue;}
    }
    

    Thanks to all the answers.
    Giorgio


  • Lifetime Qt Champion

    Hi,

    Why that infinite loop ? It looks like you should have a worker object that implements that big switch or maybe a map of int and function pointers.



  • @SGaist said in QTimer::singleShot(x00, [=]{ mysignal1; }); .... multiple time:

    Hi,

    Why that infinite loop ? It looks like you should have a worker object that implements that big switch or maybe a map of int and function pointers.

    a map of int (and I have omitted in above example the mutex and stop command)..... I have linked for each command on gui an int value that I send to mythread .... I keep checking (with a delay of 20ms) if the myvalue (int) is changed and if it is changed I work switch case ... Recalling a modbus log writing function. .... for major precision on my code there is an if before the switch/case statement .... is true if myvalue is changed .... I renew my example in above thread ... It's just a representation of the mechanism .... it works very well but sometimes the commands are not executed .... I do not think it's a problem of writing time on the modbus, so I tried to ask where I could be wrong. Is my using the signal / slot mechanism from mainwindow to myqthread wrong? .... Check back the code above ... i fixed it to make you understand better what i'm doing .... sorry but i do not have the file on this tablet.

    any how in 5.8 on linux is necessary to install libmodbus or qt5.8 have a new modbus library instead (actually I use 5.6 and program to upgrade to new 5.8)?

    regards
    giorgio


  • Lifetime Qt Champion

    What if you get two changes in a row ? One might get lost.



  • @SGaist said in QTimer::singleShot(x00, [=]{ mysignal1; }); .... multiple time:

    What if you get two changes in a row ? One might get lost.

    You are in right but is for these that I use lambda with singleshot timer .... if I must send more than one change in one command I sent one after 100ms and the second one after 600ms. In mythread myvalueIschangedTrue function must receive 1 only command at time ... If I have 2 identical command the second one is cancel, if I have 2 different command I must use lambda singleshot trick ..... But I could also make a speck of buffer for the signals .... to be able to store up to 10 signals sent in one line .... or more simply instead of the registers use the individual bits ... so I could send up to 16 signals in one line.
    But the problem is not this. The problem is: is it correct to use my trick (lambda + singleshot) to send more signals at a time or is it better to follow other roads? Yes what is it?

    HSKOGLUND WROTE: Hi, if you call your mythread void functions directly from your mainwindows signal; that means your're calling from one function to a function in another thread, and that's the reason I think why the call fails sometimes.

    So my sistem is not correct? not Understand very well .... The thing is that I still have to learn a lot of things. Anyone can tell me if what I'm doing is correct or not?

    I think I understand the "context object" affairs ... it make sense .... so I must limit the use of single shot timer + lambda .... But this does not say if my thing is correct or not.

    Thnks to all.
    Giorgio


  • Lifetime Qt Champion

    Can you provide a description of what your application should be doing exactly ?



  • @SGaist for shure ...

    I have a gui with 20 pushbutton or more .... everytime the users press a button I send one ore more modbus holding register writing .....
    the modbus master rtu is located into mythread and I have a do(;;) cicle for intercept the new value send from gui .... the switch case statement intercept the new value and call the right void with the right register number and value ...this void execute the modbus writing. .... later I attach the right signal slot sequence and the real code.

    the code:

    /***** in mainwindows ****/
    /*********************************** k::cm_xxxxxxxx_4 is a global int number  present in file  global _konst.h    *******/
    
    connect(ui->s12_2, SIGNAL(toggled(bool)), this, SLOT(sss12_2(bool)));  /*s12_2 is a pushbutton*/
    
    mThread4 = new Kmecth4(this);
    connect(this, SIGNAL(sendInOut(int,bool,int)), mThread4, SLOT(receiveNum4(int,bool,int)), Qt::DirectConnection);
    mThread4->start();
    
    
    
    
        if(MultiMachine != 0)
        {
            switch (MultiMachine) {
            case 1:
                if(cntrPC1)
                {
                    modbus_set_slave(ctx, 1);
                    ret = modbus_write_register(ctx, ModBusMultiRegNr, valueMultiReg);
                    this->msleep(10);
                    qDebug() << "stato inviato ctx 01 = " <<  " reg = " << ModBusMultiRegNr << " valore = " << valueMultiReg;
                }
                control4 = false;
                modbus_flush(ctx);
                break;
            case 2:
                if(cntrPC2)
                {
                    modbus_set_slave(ctx, 2);
                    ret = modbus_write_register(ctx, ModBusMultiRegNr, valueMultiReg);
                    this->msleep(10);
                    qDebug() << "stato inviato ctx 02 = " <<  " reg = " << ModBusMultiRegNr << " valore = " << valueMultiReg;
                }
                control4 = false;
                modbus_flush(ctx);
                break;
    /* etc etc etc......*/
    

    regards
    Giorgio


  • Lifetime Qt Champion

    Are you trying to model your modbus system with that code ? Because it looks like a state machine might be more fitting.

    On a site note, your use of QMutex in the run method is wrong, you're not protecting anything since it's a local mutex.

    By the way, Qt provides now support for modbus in the QtSerialBus module.



  • @SGaist mmmm maybe ... but I have in these case a lot of parallel state .... and the execution phisically is not on that pc ... so execution signal is returned with delay ... The add more difficult to use state machine .... In any case state machine framework seems to me something complicated to handle having many gui signals and many feedback from the outside world ... indeed the framework state machine seems to me something complicated when it could be all inserted in the struct with control/buffer function and ini files for shutdown event (at least From the examples I saw). I still have to find the example code that convinces me to use StateMachine.

    Anyway, writing on the forum I'm convinced that the heart of the problem is the delays, so I'll have to put my code so that there is not a single write function for all the commands.

    About QMutex ... you are in right.

    About new support of mudbus int QtSerialbus into QT5.8 ... I'm trying it out these days .... It sounds like a good thing and I think I'll use it instead of libmodbus.

    regards
    Giorgio


Log in to reply
 

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