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. signals and slots across threads without QThread inheritance
Forum Updated to NodeBB v4.3 + New Features

signals and slots across threads without QThread inheritance

Scheduled Pinned Locked Moved Solved General and Desktop
16 Posts 6 Posters 2.9k Views 3 Watching
  • 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.
  • SGaistS Offline
    SGaistS Offline
    SGaist
    Lifetime Qt Champion
    wrote on last edited by
    #7

    Hi,

    One very important rule with signals and slots: do not emit signal from other classes. You shall only emit from within your class implementation.

    Please take a look at the QThread documentation to see an example of the worker object approach.

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

    D 1 Reply Last reply
    2
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #8

      @dan13l said in signals and slots across threads without QThread inheritance:

      So, what I learned is to explicitly set QueuedConnection together with the new syntax, because I tried again AutoConnection and then it fails to work.

      Then you're doing something wrong and your QObject('s) don't live in the appropriate thread.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      D 1 Reply Last reply
      3
      • SGaistS SGaist

        Hi,

        One very important rule with signals and slots: do not emit signal from other classes. You shall only emit from within your class implementation.

        Please take a look at the QThread documentation to see an example of the worker object approach.

        D Offline
        D Offline
        dan13l
        wrote on last edited by
        #9

        @SGaist said in signals and slots across threads without QThread inheritance:

        One very important rule with signals and slots: do not emit signal from other classes. You shall only emit from within your class implementation.

        Hi @SGaist, thanks for that hint, I will try to implement it that way. Seems that for my real code it will be anyway necessary to create an additional object in which the emit can happen then.

        1 Reply Last reply
        0
        • Christian EhrlicherC Christian Ehrlicher

          @dan13l said in signals and slots across threads without QThread inheritance:

          So, what I learned is to explicitly set QueuedConnection together with the new syntax, because I tried again AutoConnection and then it fails to work.

          Then you're doing something wrong and your QObject('s) don't live in the appropriate thread.

          D Offline
          D Offline
          dan13l
          wrote on last edited by
          #10

          @Christian-Ehrlicher said in signals and slots across threads without QThread inheritance:

          Then you're doing something wrong and your QObject('s) don't live in the appropriate thread.

          Hmm...okay, maybe I should investigate that further. Does it make a difference, when I send the QObject to the thread through

          obj.MoveToThread(thread);
          

          and when I create the connection? What I mean is, doing:

          obj.MoveToThread(thread);
          QObject::connect(...);
          

          or doing

          QObject::connect(...);
          
          obj.MoveToThread(thread);
          
          KroMignonK 1 Reply Last reply
          0
          • D dan13l

            @Christian-Ehrlicher said in signals and slots across threads without QThread inheritance:

            Then you're doing something wrong and your QObject('s) don't live in the appropriate thread.

            Hmm...okay, maybe I should investigate that further. Does it make a difference, when I send the QObject to the thread through

            obj.MoveToThread(thread);
            

            and when I create the connection? What I mean is, doing:

            obj.MoveToThread(thread);
            QObject::connect(...);
            

            or doing

            QObject::connect(...);
            
            obj.MoveToThread(thread);
            
            KroMignonK Offline
            KroMignonK Offline
            KroMignon
            wrote on last edited by
            #11

            @dan13l There is no difference if you first move the instance to another thread or connect signals/slots first.

            Have you read the documentation Signals & Slots?

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

            D 1 Reply Last reply
            2
            • KroMignonK KroMignon

              @dan13l There is no difference if you first move the instance to another thread or connect signals/slots first.

              Have you read the documentation Signals & Slots?

              D Offline
              D Offline
              dan13l
              wrote on last edited by
              #12

              @KroMignon okay, I just wanted to give some approach for @Christian-Ehrlicher`s comment that something is still not correct, when AutoConnect does not work. Now I see that my suggestion was indeed not the best one ... πŸ™ˆ

              kshegunovK KroMignonK 2 Replies Last reply
              0
              • D dan13l

                @KroMignon okay, I just wanted to give some approach for @Christian-Ehrlicher`s comment that something is still not correct, when AutoConnect does not work. Now I see that my suggestion was indeed not the best one ... πŸ™ˆ

                kshegunovK Offline
                kshegunovK Offline
                kshegunov
                Moderators
                wrote on last edited by kshegunov
                #13

                @dan13l said in signals and slots across threads without QThread inheritance:

                okay, I just wanted to give some approach for @Christian-Ehrlicher`s comment that something is still not correct

                What Christian means is that the connection should be agnostic to the object's thread and that if you force the connection types you can hide actual bugs (i.e. an object not in the correct thread) from yourself. The subtler point is that QObject::connect already defaults to the Qt::QueuedConnection iff your object is already in a different thread, while you can see in the stack that it was directly invoked if in fact you have a slot executed before the object's been moved. All in all: do not force the connection type to queued unless you actually need to call the slot in the same thread but later (i.e. through the event loop).

                Read and abide by the Qt Code of Conduct

                1 Reply Last reply
                4
                • D dan13l

                  @KroMignon okay, I just wanted to give some approach for @Christian-Ehrlicher`s comment that something is still not correct, when AutoConnect does not work. Now I see that my suggestion was indeed not the best one ... πŸ™ˆ

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

                  @dan13l It could be hard to understand at beginning how signals/slots works. But is a fundamental mechanism in Qt world.
                  The connection type should never be specified (which means it is "automatic").
                  In automatic mode, the connection mode will be decide at signal call:

                  • when source and destination QObject are in same thread, direct connection will be used
                  • when source and destination QObject are in different thread queued connection will be used

                  By using queued connection, a shadow copy of each parameter will be done and used for the slot call. And the call will be registered in event queue from destination thread, executed when entering in the event queue. So it will be delayed.
                  This mechanism can simplify multi-threading communication, but you have to be aware that a copy of each parameter will always be done!

                  In direct connection, the call will be done directly, like a function call without shadow copy.

                  Hope this will help you.

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

                  1 Reply Last reply
                  2
                  • S Offline
                    S Offline
                    SimonSchroeder
                    wrote on last edited by
                    #15

                    The first thing I see in the code is that there is not possibility for A to further process any events.

                    If you do:

                    QThread* thread = new QThread;
                    ...
                    thread->start();
                    

                    it will use the default implementation of QThread which will run an event loop.

                    In between creating the thread and starting it you do:

                    QObject::connect(thread, SIGNAL(started()), &a, SLOT(processList()), Qt::AutoConnection);
                    

                    which means that when the thread starts it will immediately start processing the first slot processList. Only after this slot finishes will the thread be able to process the next event from its event loop. However, you have a

                    while(running)
                    {
                        ...
                    }
                    

                    in you processList slot. So, I guess that your slot never finishes and QThread will never pick up any other events.

                    One trick you can try is to put a repeating QTimer in your thread which has a timeout of 0ms and is connected to processList (assuming you remove the while(running)...). This will call processList over and over again when there is nothing else to do (kind of an infinite loop like you have now). But, between calls to processList other events can be handled, i.e. executing makeUpdate in your specific case.

                    1 Reply Last reply
                    2
                    • D Offline
                      D Offline
                      dan13l
                      wrote on last edited by
                      #16

                      Thank you again for your engagement regarding my questions! πŸ™‚

                      @kshegunov ah, okay, so thank you for that explanation. I think now the example code is improved, because I need no specification for the Connection Type. (see below)

                      @KroMignon also thanks to you for the deeper insight to to Connection Types. Yes, it helps me, also regarding some code efficiency considerations due to the creation of shallow copies.

                      @SimonSchroeder Thanks a lot! First I did not think about further events, but in the end this is what I want to achieve. Therefore your 'trick' addresses directly my implementation problem and solves it. Fantastic!
                      I hope I understood your idea correctly? What I did is the following:

                      main.cxx

                      #include <QApplication>
                      #include <QThread>
                      #include <iostream>
                      #include "A.h"
                      #include "B.h"
                      int main(int argc , char *argv[]){
                        QApplication app(argc, argv);
                        //doing something for gui and user ...
                        // ...
                        std::cout<<"Hello Qt Forum."<<std::endl;
                        // ...
                        A a(1);
                        B b(2);
                        //creating thread 
                        QThread* thread = new QThread;
                        a.moveToThread(thread); // change thread affinity
                        bool check1, check2;
                        check1 = QObject::connect(thread, &QThread::started, &a, &A::timing);
                        check2 = QObject::connect(&b, &B::updater , &a, &A::makeUpdate);
                        std::cout<<"successful connection?: check1= "<<check1<<" and check2= "<<check2<<std::endl;
                      
                        //starting thread
                        thread->start();
                        
                        //now: give an update from B to A:
                        emit b.updater(42); // --> now it`s working
                        for(int i = 0; i < 123; i++) std::cout<<"here in main with i = "<<i<<std::endl;
                        emit b.updater(1001);// --> and again...
                        return app.exec();
                      }
                      

                      A.cxx (t is my timer defined in A.h with this=A as parent. Otherwise it will give me 'QObject::killTimer: Timers cannot be stopped from another thread' . I think it is due to different thread affinity.

                      #include "A.h"
                      #include <iostream>
                      //
                      A::A (int id){
                        name = id;
                        t->callOnTimeout(this, &A::processList);
                      }
                      
                      void A::timing(){
                        std::cout<<thread()<<std::endl;
                          t->start();
                        
                      }
                      
                      void A::processList(){
                        std::cout<<"in processList"<<std::endl;
                        if( !buffer.isEmpty() ){
                          list.append(buffer);
                          std::cout<<"Now list size is: "<<list.size()<<std::endl;
                          buffer.clear();
                          std::cout<<"after cleaning buffer, buffer size is:"<<buffer.size()<<std::endl;
                        }
                        timing();
                      }
                      
                      void A::makeUpdate( int update ){
                        std::cout<<"Updating..."<<std::endl;
                        std::cout<<thread()<<std::endl;
                        buffer.append(update);
                      }
                      
                      

                      as my result, my console output gives me the following:

                      Hello Qt Forum.
                      successful connection?: check1= 1 and check2= 1
                      here in main with i = 0
                      here in main with i = 1
                      here in main with i = 2
                      here in main with i = 3
                      ...
                      0x16571e8
                      ...
                      Updating...
                      0x16571e8
                      ...
                      here in main with i = 40
                      here in main with i = 41
                      ...
                      in processList
                      Now list size is: 1
                      after cleaning buffer, buffer size is:0
                      0x16571e8
                      ...
                      here in main with i = 100
                      here in main with i = 101
                      ...
                      here in main with i = 122
                      in processList
                      0x16571e8
                      Updating...
                      0x16571e8
                      in processList
                      Now list size is: 2
                      after cleaning buffer, buffer size is:0
                      0x16571e8
                      in processList
                      ...
                      
                      1 Reply Last reply
                      0

                      • Login

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