Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Call for Presentations - Qt World Summit

    Solved Problems with signals and slots in separate threads

    General and Desktop
    3
    6
    1075
    Loading More Posts
    • 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.
    • H
      Henduww last edited by

      So I'm trying to make a fairly simple signal/slot setup with a thread sending the signal, and my main application picking up on it with a slot.
      I've been adviced not to subclass QThread, so I'm using a QThread object running an object of my own class.

      The abstract idea here is that I have a class "A" (main application), that has a slot "slot_a". My other class "B", has a signal "signal_b".
      In As constructor, a thread member is initialized, and an object of type B is moved into said thread. I then proceed to connect signal_b to slot_a. (Thread emits signal, main application receives it)
      This is where the problem occurs: The signal is indeed emitted, but the slot is never reached, unless I use Qt::DirectConnection, which I can't use, because the slot is supposed to update a couple of UI elements.

      Relevant code:
      A's constructor

      A::A(QWidget *parent)
      	: QMainWindow(parent), b_member(new B()), controllerThread(this)
      {
      	ui.setupUi(this);
      
      	b_member->moveToThread(&controllerThread);
      	QObject::connect(&controllerThread, &QThread::started, b_member, &B::slot_b); //this works just fine, "slot_b" is executed
      	QObject::connect(connectionHandler, &B::signal_b, this, &A::slot_a); // here, it only works with Qt:DirectConnection, which I DON'T want
              controllerThread->start(QThread::Priority::HighestPriority);
      }
      

      slot_a:

      void A::slot_a(const MyEnum check)
      {
              // this code is never reached. Breakpoint confirms that
      	if (check == MyEnum::SOMECHECK)
      	{
      		ui.label_someLabel->setVisible(false);
      	}
      	else if (check == MyEnum::SOMEOTHERCHECK)
      	{
      		ui.label_someLabel->setVisible(true);
      	}
      }
      // I need a QueuedConnection for this to work, apparently. Evidently does not work with DirectConnection at least. Causes runtime exception.
      

      signal_b: (defined in b.h)

      void signal_b(const MyEnum);
      

      signal_b is emitted from slot_b as such:

      void B::slot_b()
      {
          // this code is reached and executed
          emit signal_b(MyEnum::SOMECHECK);
      }
      

      Not sure if it's even relevant, or just a property of Qt and VS, but following the emition of singal_b just leads me to "qobject.cpp not found".

      I've spent far too many hours looking into this problem, and according to multiple other forum posts and stack overflow topics, I've done everything right.
      If anything's unclear, I'd be glad to clear it up. Thanks in advance!

      aha_1980 1 Reply Last reply Reply Quote 0
      • aha_1980
        aha_1980 Lifetime Qt Champion @Henduww last edited by

        Hi @Henduww,

        the connection types are described here.

        Qt::DirectConnection 1 The slot is invoked immediately when the signal is emitted. The slot is executed in the signalling thread.

        This means, a function call takes place, therefore your breakpoint is hit and the runtime problems occur.

        Qt::QueuedConnection 2 The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.

        Here the function call is put in a mailbox of the receiver and is executed when the event loop has time for it.

        That leads me to the question: do you have an event loop running in the receiver thread?

        but following the emition of singal_b just leads me to "qobject.cpp not found".

        What do you mean by that?

        Regards

        Qt has to stay free or it will die.

        1 Reply Last reply Reply Quote 3
        • H
          Henduww last edited by

          Thanks for clearing those things up @aha_1980!
          I'm not sure how to implement an event loop, didn't realize I had to do that, but I'll look into it :)
          By the qobject.cpp not found I mean after following the emitting with breakpoints, I follow it into the moc file of my header, then I get led to "qobject.cpp" not found in Visual Studio. I don't think it's an error though, probably just VS that doesn't know how to step through the emition.

          1 Reply Last reply Reply Quote 1
          • BjornW
            BjornW last edited by BjornW

            You should already have two event loops running, no need to create one yourself. When you do:

            controllerThread->start(QThread::Priority::HighestPriority);
            

            you start the controller thread event loop.

            I assume your widget "A" is running in the main thread (it has to?). When you do the typical

            return app.exec() 
            

            in main function you start the event loop on the main thread.

            You should now have two event loops running. What you need to look out for is what kind of arguments you are passing around in the signals/slots. In direct connections you can pass anything. If you want to pass anything over a queued connection you need to register the types with the qt meta system (most basic types such as ints etc are already registered). What are you sending? You shoul get a warning in your console if you try to pass anything that is unregistered.

            1 Reply Last reply Reply Quote 5
            • BjornW
              BjornW last edited by

              Did you work it out?

              H 1 Reply Last reply Reply Quote 0
              • H
                Henduww @BjornW last edited by

                @BjornW Thank you so much for clearing that up with the meta-types, that was indeed the problem!
                I've been on vacation the past week, so sorry for the delayed answer.
                The type I was passing was an enum class, which really wasn't necessary. I just changed it to a regular enum and made the signal/slots use int to make use of enums' implicit casting, works like a charm!

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post