Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Signal and slot to synchronize variable between qthread
QtWS25 Last Chance

Signal and slot to synchronize variable between qthread

Scheduled Pinned Locked Moved Unsolved General and Desktop
qthreadsignal & slotdesign pattern
11 Posts 5 Posters 6.9k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    SGaist
    Lifetime Qt Champion
    wrote on 27 Apr 2017, 22:48 last edited by
    #2

    Hi and welcome to devnet,

    There are mainly two reasons: your MyClass objects have both undefined values for myVar which means they will both change when setMyVar is called.

    Then, AFAIK, it's because of the queued connection that results from connecting two objects in different threads. The signal emissions will queue events to the event loop of the thread to which the object has affinity with thus your first call to setMyVar will generate an event sent to the main thread object that will then generate another event that will be sent back to the worker object which will have generated another one in between with the second call to setMyVar.

    Interested in AI ? www.idiap.ch
    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

    1 Reply Last reply
    4
    • R Offline
      R Offline
      RausoV
      wrote on 28 Apr 2017, 17:30 last edited by
      #3

      Hi SGaist, thank you for your answer.
      I think that the main reason is number two: queued connections. In fact even if I initialize myVar (obviously with a value different from "first", the first set) the infinite loop remains.
      This kind of connections it's the only possible between different threads; I tried blocking connections also because I thought that a thread is blocked and cannot send another setMyVar signal before the other thread finished it's myVar update.
      Obviously this is only a sample code of what I'm doing, maybe it's a design mistake and so here I'm looking for the right solution.

      1 Reply Last reply
      0
      • S Offline
        S Offline
        SGaist
        Lifetime Qt Champion
        wrote on 28 Apr 2017, 20:23 last edited by
        #4

        Initialised with a value other than first and second will have the same effect has having them uninitialised.

        What exactly are you trying to accomplish ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        0
        • R Offline
          R Offline
          RausoV
          wrote on 3 May 2017, 12:39 last edited by
          #5

          Like I said, the information that myVar contains has to be equal in two different threads. If one changes so the other has to be updated.
          Obviously the code above is a simplification of a bigger one, but it's the problem's core.

          J 1 Reply Last reply 3 May 2017, 13:01
          0
          • R RausoV
            3 May 2017, 12:39

            Like I said, the information that myVar contains has to be equal in two different threads. If one changes so the other has to be updated.
            Obviously the code above is a simplification of a bigger one, but it's the problem's core.

            J Online
            J Online
            J.Hilk
            Moderators
            wrote on 3 May 2017, 13:01 last edited by
            #6

            @RausoV Well that problem should be easy enough to solve. Expand void myVarChanged(QString value); by a thread Inique Identifier.

            void myVarChanged(QString value, int UniqueID);
            

            then in your slot compare if the ID fits the own ID.
            if it does -> do nothing, else accept new value, but don't emit the Signal.

            void Worker::setMyVar(const QString &value, int id)
            {
                   if(id == ownID)
            	  myObject->setMyVar(value); //set Variable with signal?
                  else
                      myObject->setVarWithoutSignal(value);
            }
            

            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            B 1 Reply Last reply 3 May 2017, 15:12
            0
            • R Offline
              R Offline
              RausoV
              wrote on 3 May 2017, 15:08 last edited by
              #7

              Hi J.Hilk,
              thank you for joining this discussion. Your idea works well on this example and I had already taken it in consideration, but it changes the myClass implementation. In my project there are several existent classes and I'd like to avoid to change them.
              I'd like to change only the worker class or add a new class dedicated to the synchronization purpose.

              K 1 Reply Last reply 3 May 2017, 15:26
              0
              • J J.Hilk
                3 May 2017, 13:01

                @RausoV Well that problem should be easy enough to solve. Expand void myVarChanged(QString value); by a thread Inique Identifier.

                void myVarChanged(QString value, int UniqueID);
                

                then in your slot compare if the ID fits the own ID.
                if it does -> do nothing, else accept new value, but don't emit the Signal.

                void Worker::setMyVar(const QString &value, int id)
                {
                       if(id == ownID)
                	  myObject->setMyVar(value); //set Variable with signal?
                      else
                          myObject->setVarWithoutSignal(value);
                }
                
                B Offline
                B Offline
                BjornW
                wrote on 3 May 2017, 15:12 last edited by
                #8

                @J.Hilk

                Does that truly work, though?

                Imagine, in two different treads, the value is set to "A" and "B" respectively and simultaneously. From each thread the corresponding event is posted to the other thread.

                A->B: setMyVar("A", id_a)
                B->A: setMyVar("B", id_b)

                on the receiving end, as the event queue is processed:

                A: setMyVar("B", id_b) --> "not my thread" -> set without signal
                B: setMyVar("A", id_a) --> "not my thread" -> set without signal

                A and B are now out of sync.

                What did I miss?

                1 Reply Last reply
                0
                • R RausoV
                  3 May 2017, 15:08

                  Hi J.Hilk,
                  thank you for joining this discussion. Your idea works well on this example and I had already taken it in consideration, but it changes the myClass implementation. In my project there are several existent classes and I'd like to avoid to change them.
                  I'd like to change only the worker class or add a new class dedicated to the synchronization purpose.

                  K Offline
                  K Offline
                  kshegunov
                  Moderators
                  wrote on 3 May 2017, 15:26 last edited by
                  #9
                  QObject::connect(&myObject, &MyClass::myVarChanged, &worker, &Worker::setMyVar, Qt::BlockingQueuedConnection);
                  QObject::connect(&worker, &Worker::myVarChanged, &myObject, &MyClass::setMyVar);
                  

                  Should work fine, but I really doubt the wisdom of doing those shenanigans ...

                  Read and abide by the Qt Code of Conduct

                  1 Reply Last reply
                  0
                  • B Offline
                    B Offline
                    BjornW
                    wrote on 3 May 2017, 15:59 last edited by
                    #10

                    I would separate the objects into two types. One type that is the "master" object and other objects which interact with it.

                    Disclaimer: I didn't compile this stuff

                    class MyObject : public QObject
                    {
                       Q_OBJECT
                    public:
                       Q_SIGNAL void valueChanged(QString);
                       Q_SLOT void setValue(QString value) //Intended to be called by business logic
                       {
                          m_value = value;
                          emit valueChanged(value);
                       }
                       Q_SLOT void sync(QString value) //Intended to be called by the "master" object.
                       {
                          m_value = value;
                       }
                    private:
                       QString m_value;
                    };
                    ...
                    
                    main.cpp:
                    
                    MyObject objectA;  //Goes to thread A
                    MyObject objectB;  //Goes to thread B
                    MyObject master;   //Goes "somewhere neutral"
                    
                    //Notify the master object when A/B changes
                    QObject::connect(&objectA, &MyObject::valueChanged, &master, &MyObject::setValue);
                    QObject::connect(&objectB, &MyObject::valueChanged, &master, &MyObject::setValue);
                    
                    //Sync A/B with master
                    QObject::connect(&master, &MyObject::valueChanged, &objectA, &MyObject::sync);
                    QObject::connect(&master, &MyObject::valueChanged, &objectB, &MyObject::sync);
                    
                    QThread threadA;
                    QThread threadB;
                    objectA.moveToThread(&threadA);
                    objectB.moveToThread(&threadB);
                    threadA.start();
                    threadB.start();
                    
                    K 1 Reply Last reply 3 May 2017, 16:18
                    0
                    • B BjornW
                      3 May 2017, 15:59

                      I would separate the objects into two types. One type that is the "master" object and other objects which interact with it.

                      Disclaimer: I didn't compile this stuff

                      class MyObject : public QObject
                      {
                         Q_OBJECT
                      public:
                         Q_SIGNAL void valueChanged(QString);
                         Q_SLOT void setValue(QString value) //Intended to be called by business logic
                         {
                            m_value = value;
                            emit valueChanged(value);
                         }
                         Q_SLOT void sync(QString value) //Intended to be called by the "master" object.
                         {
                            m_value = value;
                         }
                      private:
                         QString m_value;
                      };
                      ...
                      
                      main.cpp:
                      
                      MyObject objectA;  //Goes to thread A
                      MyObject objectB;  //Goes to thread B
                      MyObject master;   //Goes "somewhere neutral"
                      
                      //Notify the master object when A/B changes
                      QObject::connect(&objectA, &MyObject::valueChanged, &master, &MyObject::setValue);
                      QObject::connect(&objectB, &MyObject::valueChanged, &master, &MyObject::setValue);
                      
                      //Sync A/B with master
                      QObject::connect(&master, &MyObject::valueChanged, &objectA, &MyObject::sync);
                      QObject::connect(&master, &MyObject::valueChanged, &objectB, &MyObject::sync);
                      
                      QThread threadA;
                      QThread threadB;
                      objectA.moveToThread(&threadA);
                      objectB.moveToThread(&threadB);
                      threadA.start();
                      threadB.start();
                      
                      K Offline
                      K Offline
                      kshegunov
                      Moderators
                      wrote on 3 May 2017, 16:18 last edited by
                      #11

                      @BjornW said in Signal and slot to synchronize variable between qthread:

                      I would separate the objects into two types. One type that is the "master" object and other objects which interact with it.

                      That's the correct thinking, I consider this whole question to be a design issue. The problem I see is that a dependency is introduced between two QObjects that are in different threads, that is very unnatural to begin with - the two objects shouldn't depend on one another implicitly; it's no mistake that a QObject instance can't have a parent that's living in another thread. In my mind either the dependency should be declared explicitly (e.g. manually synchronizing the objects across the threads in some fashion) or it shouldn't exist at all.

                      Read and abide by the Qt Code of Conduct

                      1 Reply Last reply
                      1

                      11/11

                      3 May 2017, 16:18

                      • Login

                      • Login or register to search.
                      11 out of 11
                      • First post
                        11/11
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved