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. Is it safe to emit a signal from another thread than the QObject?

Is it safe to emit a signal from another thread than the QObject?

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 4 Posters 3.2k 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.
  • A Offline
    A Offline
    andyP
    wrote on last edited by andyP
    #1

    In my code I have a class like this:

    // created in main thread:
    class Model : public QObject {
      Q_OBJECT
    signals:
      void statusMessage(QString msg);
    public:
      void sendStatusMessage(QString msg) { // called from non main thread
          emit statusMessage(msg);
      }
    };
    

    This signal is connected to a slot that displays the message in the gui:

    connect(model, // main thread 
            &Model::statusMessage, 
            this, // main thread 
    	&StatusText::addMessage);
    

    So I tell connect that the signal will be emitted from the main thread and still emits it from a non main thread.
    Is this safe or undefined behaviour? It appears to be working.

    How can I achieve what I am trying to do in a safe manner?

    Is it sufficient to add a Qt::QueuedConnection argument to connect?

    If not I guess turning sendMessage() into a slot and calling:

    QMetaObject::invokeMethod(m_model, "sendMessage", Qt::QueuedConnection, Q_ARG(QString, qmessage));
    

    from non main threads would work?
    However I find that a not very elegant solution.

    KroMignonK 1 Reply Last reply
    0
    • A andyP

      @KroMignon: thank you for your help. From the documentation: "Qt::AutoConnection: If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used."

      So there is an assymetry here. It checks in which thread the receiver lives: receiver->thread().
      But it do NOT check in which thread the sender lives (sender->thread()).
      Instead it checks from which thread the signal is emitted: QThread::currentThread().

      So it seems that in which thread a QObject lives (affinity) and in which thread a method is running are two different things.
      A QObject lives in only one thread, which is the one it was created in (unless it has been moveToThread).
      The methods of an QObject on the other hand may be called from many different threads.

      Therefore the code is safe and the documentation explains why it is safe.
      It is just that is a bit counterintuitive.

      KroMignonK Offline
      KroMignonK Offline
      KroMignon
      wrote on last edited by
      #9

      @andyP said in Is it safe to emit a signal from another thread than the QObject?:

      Therefore the code is safe and the documentation explains why it is safe.
      It is just that is a bit counterintuitive.

      When multi-threading is used, there are many things which are not intuitive ;-)
      Using signals/slots mechanism often simplifies data exchanges, but you have to be aware that, depending on parameter types, copies may be expensive!

      It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

      J.HilkJ 1 Reply Last reply
      2
      • A andyP

        In my code I have a class like this:

        // created in main thread:
        class Model : public QObject {
          Q_OBJECT
        signals:
          void statusMessage(QString msg);
        public:
          void sendStatusMessage(QString msg) { // called from non main thread
              emit statusMessage(msg);
          }
        };
        

        This signal is connected to a slot that displays the message in the gui:

        connect(model, // main thread 
                &Model::statusMessage, 
                this, // main thread 
        	&StatusText::addMessage);
        

        So I tell connect that the signal will be emitted from the main thread and still emits it from a non main thread.
        Is this safe or undefined behaviour? It appears to be working.

        How can I achieve what I am trying to do in a safe manner?

        Is it sufficient to add a Qt::QueuedConnection argument to connect?

        If not I guess turning sendMessage() into a slot and calling:

        QMetaObject::invokeMethod(m_model, "sendMessage", Qt::QueuedConnection, Q_ARG(QString, qmessage));
        

        from non main threads would work?
        However I find that a not very elegant solution.

        KroMignonK Offline
        KroMignonK Offline
        KroMignon
        wrote on last edited by
        #2

        @andyP said in Is it safe to emit a signal from another thread than the QObject?:

        So I tell connect that the signal will be emitted from the main thread and still emits it from a non main thread.

        Not really, signal is from instance model to instance this, the used thread is not relevant for the connect statement. It will be checked when signal emitted.
        As you should known, the instances may be moved to another thread at anytime, event after connect was done.

        How can I achieve what I am trying to do in a safe manner?

        Why do you think this is not safe?

        It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

        jsulmJ A 2 Replies Last reply
        0
        • KroMignonK KroMignon

          @andyP said in Is it safe to emit a signal from another thread than the QObject?:

          So I tell connect that the signal will be emitted from the main thread and still emits it from a non main thread.

          Not really, signal is from instance model to instance this, the used thread is not relevant for the connect statement. It will be checked when signal emitted.
          As you should known, the instances may be moved to another thread at anytime, event after connect was done.

          How can I achieve what I am trying to do in a safe manner?

          Why do you think this is not safe?

          jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on last edited by
          #3

          @KroMignon said in Is it safe to emit a signal from another thread than the QObject?:

          Why do you think this is not safe?

          Because sendStatusMessage(QString msg) is called from another thread (for whatever reason).

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          KroMignonK 1 Reply Last reply
          2
          • jsulmJ jsulm

            @KroMignon said in Is it safe to emit a signal from another thread than the QObject?:

            Why do you think this is not safe?

            Because sendStatusMessage(QString msg) is called from another thread (for whatever reason).

            KroMignonK Offline
            KroMignonK Offline
            KroMignon
            wrote on last edited by
            #4

            @jsulm said in Is it safe to emit a signal from another thread than the QObject?:

            Because sendStatusMessage(QString msg) is called from another thread (for whatever reason).

            Again, what is the problem?
            msg is passed as copy, so I cannot see any problem. Maybe I am blind?

            It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

            jsulmJ 1 Reply Last reply
            0
            • KroMignonK KroMignon

              @jsulm said in Is it safe to emit a signal from another thread than the QObject?:

              Because sendStatusMessage(QString msg) is called from another thread (for whatever reason).

              Again, what is the problem?
              msg is passed as copy, so I cannot see any problem. Maybe I am blind?

              jsulmJ Offline
              jsulmJ Offline
              jsulm
              Lifetime Qt Champion
              wrote on last edited by
              #5

              @KroMignon I also think there is no problem, just wanted to point out why OP is in doubt.

              https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              1
              • KroMignonK KroMignon

                @andyP said in Is it safe to emit a signal from another thread than the QObject?:

                So I tell connect that the signal will be emitted from the main thread and still emits it from a non main thread.

                Not really, signal is from instance model to instance this, the used thread is not relevant for the connect statement. It will be checked when signal emitted.
                As you should known, the instances may be moved to another thread at anytime, event after connect was done.

                How can I achieve what I am trying to do in a safe manner?

                Why do you think this is not safe?

                A Offline
                A Offline
                andyP
                wrote on last edited by andyP
                #6

                @KroMignon: thank you.
                StatusText::addMessage() works on a QWidget so it should not be called from a non main thread?
                Therefore a direct connection from Model::statusMessage() to StatusText::addMessage() must not be made?
                As you mention the thread of the sender and receiver is not checked when I call connect() but rather when the signal is emitted.
                But how is this done?
                I do not moveToThread() anywhere in my code.
                I was assuming that the QObject::thread() would be called on both the Model and the StatusText.
                I was also assuming that the QObject::thread() of a QObject that has not been moveToThread() would equal the thread in which the QObject was created.
                The result of this test following my logic would be that both sender and receiver has affinity with the main thread and a direct call should therefore be made.
                Which in turn should crash. But it does not.

                KroMignonK 1 Reply Last reply
                0
                • A andyP

                  @KroMignon: thank you.
                  StatusText::addMessage() works on a QWidget so it should not be called from a non main thread?
                  Therefore a direct connection from Model::statusMessage() to StatusText::addMessage() must not be made?
                  As you mention the thread of the sender and receiver is not checked when I call connect() but rather when the signal is emitted.
                  But how is this done?
                  I do not moveToThread() anywhere in my code.
                  I was assuming that the QObject::thread() would be called on both the Model and the StatusText.
                  I was also assuming that the QObject::thread() of a QObject that has not been moveToThread() would equal the thread in which the QObject was created.
                  The result of this test following my logic would be that both sender and receiver has affinity with the main thread and a direct call should therefore be made.
                  Which in turn should crash. But it does not.

                  KroMignonK Offline
                  KroMignonK Offline
                  KroMignon
                  wrote on last edited by KroMignon
                  #7

                  @andyP

                  As you mention the thread of the sender and receiver is not checked when I call connect() but rather when the signal is emitted.
                  But how is this done?

                  When you declare a signal, the MOC (Meta Object Compiler) will create a function for you (cf. https://doc.qt.io/qt-5/why-moc.html).
                  "Emitting" as signal, is in fact calling this function. The Qt emit keyword is in fact a #define to nothing. It is a semantic suggar.

                  I do not moveToThread() anywhere in my code.
                  I was assuming that the QObject::thread() would be called on both the Model and the StatusText.
                  I was also assuming that the QObject::thread() of a QObject that has not been moveToThread() would equal the thread in which the QObject was created.
                  The result of this test following my logic would be that both sender and receiver has affinity with the main thread and a direct call should therefore be made.
                  Which in turn should crash. But it does not.

                  The code automatic generated by the moc will check in which thread the destination is running on signal call and will create copies of the parameters if required - depending of the connection type (direct, queued, auto) ==> cf https://doc.qt.io/qt-5/signalsandslots.html.

                  It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                  A 1 Reply Last reply
                  3
                  • KroMignonK KroMignon

                    @andyP

                    As you mention the thread of the sender and receiver is not checked when I call connect() but rather when the signal is emitted.
                    But how is this done?

                    When you declare a signal, the MOC (Meta Object Compiler) will create a function for you (cf. https://doc.qt.io/qt-5/why-moc.html).
                    "Emitting" as signal, is in fact calling this function. The Qt emit keyword is in fact a #define to nothing. It is a semantic suggar.

                    I do not moveToThread() anywhere in my code.
                    I was assuming that the QObject::thread() would be called on both the Model and the StatusText.
                    I was also assuming that the QObject::thread() of a QObject that has not been moveToThread() would equal the thread in which the QObject was created.
                    The result of this test following my logic would be that both sender and receiver has affinity with the main thread and a direct call should therefore be made.
                    Which in turn should crash. But it does not.

                    The code automatic generated by the moc will check in which thread the destination is running on signal call and will create copies of the parameters if required - depending of the connection type (direct, queued, auto) ==> cf https://doc.qt.io/qt-5/signalsandslots.html.

                    A Offline
                    A Offline
                    andyP
                    wrote on last edited by
                    #8

                    @KroMignon: thank you for your help. From the documentation: "Qt::AutoConnection: If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used."

                    So there is an assymetry here. It checks in which thread the receiver lives: receiver->thread().
                    But it do NOT check in which thread the sender lives (sender->thread()).
                    Instead it checks from which thread the signal is emitted: QThread::currentThread().

                    So it seems that in which thread a QObject lives (affinity) and in which thread a method is running are two different things.
                    A QObject lives in only one thread, which is the one it was created in (unless it has been moveToThread).
                    The methods of an QObject on the other hand may be called from many different threads.

                    Therefore the code is safe and the documentation explains why it is safe.
                    It is just that is a bit counterintuitive.

                    KroMignonK 1 Reply Last reply
                    0
                    • A andyP

                      @KroMignon: thank you for your help. From the documentation: "Qt::AutoConnection: If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used."

                      So there is an assymetry here. It checks in which thread the receiver lives: receiver->thread().
                      But it do NOT check in which thread the sender lives (sender->thread()).
                      Instead it checks from which thread the signal is emitted: QThread::currentThread().

                      So it seems that in which thread a QObject lives (affinity) and in which thread a method is running are two different things.
                      A QObject lives in only one thread, which is the one it was created in (unless it has been moveToThread).
                      The methods of an QObject on the other hand may be called from many different threads.

                      Therefore the code is safe and the documentation explains why it is safe.
                      It is just that is a bit counterintuitive.

                      KroMignonK Offline
                      KroMignonK Offline
                      KroMignon
                      wrote on last edited by
                      #9

                      @andyP said in Is it safe to emit a signal from another thread than the QObject?:

                      Therefore the code is safe and the documentation explains why it is safe.
                      It is just that is a bit counterintuitive.

                      When multi-threading is used, there are many things which are not intuitive ;-)
                      Using signals/slots mechanism often simplifies data exchanges, but you have to be aware that, depending on parameter types, copies may be expensive!

                      It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                      J.HilkJ 1 Reply Last reply
                      2
                      • KroMignonK KroMignon

                        @andyP said in Is it safe to emit a signal from another thread than the QObject?:

                        Therefore the code is safe and the documentation explains why it is safe.
                        It is just that is a bit counterintuitive.

                        When multi-threading is used, there are many things which are not intuitive ;-)
                        Using signals/slots mechanism often simplifies data exchanges, but you have to be aware that, depending on parameter types, copies may be expensive!

                        J.HilkJ Offline
                        J.HilkJ Offline
                        J.Hilk
                        Moderators
                        wrote on last edited by J.Hilk
                        #10

                        @KroMignon said in Is it safe to emit a signal from another thread than the QObject?:

                        Using signals/slots mechanism often simplifies data exchanges, but you have to be aware that, depending on parameter types, copies may be expensive!

                        @andyP and, if you pass custom classes/structs as parameters in the signals, you have to make sure they have a correct copy constructor/operator and are registers correctly with the metasytsem


                        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.

                        A 1 Reply Last reply
                        3
                        • J.HilkJ J.Hilk

                          @KroMignon said in Is it safe to emit a signal from another thread than the QObject?:

                          Using signals/slots mechanism often simplifies data exchanges, but you have to be aware that, depending on parameter types, copies may be expensive!

                          @andyP and, if you pass custom classes/structs as parameters in the signals, you have to make sure they have a correct copy constructor/operator and are registers correctly with the metasytsem

                          A Offline
                          A Offline
                          andyP
                          wrote on last edited by andyP
                          #11

                          @J-Hilk: thank you. Regarding that I have several classes like:

                          struct PASHR {
                              std::string utcTime; // hhmmss.ss
                              double trueHeading     = 999.0;
                              int GNSSQuality = 0;
                              enum class AlignmentStatus { GPSOnly = 0, CoarseLevelling = 1, DegradedSolution = 2, Aligned = 3, FullNavigationMode = 4 };
                              AlignmentStatus alignmentStatus = AlignmentStatus::GPSOnly;
                              bool parseFromString(const std::string& line);
                          };
                          Q_DECLARE_METATYPE(PASHR);
                          

                          Here is part of my main():

                          int main(int argc, char* argv[])
                          {
                              QApplication a(argc, argv);
                              qRegisterMetaType<std::string>();
                              qRegisterMetaType<PASHR>();
                              ...
                          }
                          

                          I emit PASHR by value across threads.
                          Is this safe?

                          I am assuming that the default copy constructor and assignment operator are just fine?

                          Do I have to take some extra step regarding the enum class?

                          J.HilkJ 1 Reply Last reply
                          0
                          • A andyP

                            @J-Hilk: thank you. Regarding that I have several classes like:

                            struct PASHR {
                                std::string utcTime; // hhmmss.ss
                                double trueHeading     = 999.0;
                                int GNSSQuality = 0;
                                enum class AlignmentStatus { GPSOnly = 0, CoarseLevelling = 1, DegradedSolution = 2, Aligned = 3, FullNavigationMode = 4 };
                                AlignmentStatus alignmentStatus = AlignmentStatus::GPSOnly;
                                bool parseFromString(const std::string& line);
                            };
                            Q_DECLARE_METATYPE(PASHR);
                            

                            Here is part of my main():

                            int main(int argc, char* argv[])
                            {
                                QApplication a(argc, argv);
                                qRegisterMetaType<std::string>();
                                qRegisterMetaType<PASHR>();
                                ...
                            }
                            

                            I emit PASHR by value across threads.
                            Is this safe?

                            I am assuming that the default copy constructor and assignment operator are just fine?

                            Do I have to take some extra step regarding the enum class?

                            J.HilkJ Offline
                            J.HilkJ Offline
                            J.Hilk
                            Moderators
                            wrote on last edited by
                            #12

                            @andyP its basically a collection of basic types :D the default copy operations should do just fine.

                            Do I have to take some extra step regarding the enum class?

                            I don't hink so


                            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.

                            1 Reply Last reply
                            1

                            • Login

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