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. Problem with signal-slot connection across threads [SOLVED]
Forum Updated to NodeBB v4.3 + New Features

Problem with signal-slot connection across threads [SOLVED]

Scheduled Pinned Locked Moved General and Desktop
11 Posts 4 Posters 7.9k Views 1 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.
  • F Offline
    F Offline
    frankiefrank
    wrote on 7 Mar 2014, 17:26 last edited by
    #1

    I know this should pretty much work "out of the box" if you pay attention to some details, which I tried to - but I must have missed something.

    I have a worker thread which starts another worker thread let's call it subworker. The worker and the subworker need to communicate via signals and slots. I make all the connections from the worker thread, and all the connect() statements return true when running (also, there's no warnings reported in the debug output).

    The relevant worker thread code looks like this:
    @
    //! The subworker will live in its own thread
    subWorkerThread = new QThread(this);
    subWorkerObj.moveToThread(subWorkerThread);

    //! Let it live!
    subWorkerThread->start();

    bool ok = connect(this, SIGNAL(work(QString)), &subWorkerObj, SLOT(beginWork(QString)));
    ok = connect(&subWorkerObj, SIGNAL(signalFromSubWorker()), this, SLOT(handleSignalFromSubWorker()));
    @

    Then inside the subWorkerObj::beginWork:
    @
    emit signalFromSubWorker();
    @

    My debugging shows me that the beginWork() slot is correctly hit, but after the signal from SubWorker is emitted, I'm not hitting the breakpoint inside the handleSignalFromSubWorker() slot.

    Both classes subclass QObject (or a QObject subclass), both have the Q_OBJECT macro, and I made the slot in the worker public just in case.

    I'd appreciate any help, even about how to better debug it.

    "Roads? Where we're going, we don't need roads."

    1 Reply Last reply
    0
    • C Offline
      C Offline
      code_fodder
      wrote on 7 Mar 2014, 20:32 last edited by
      #2

      difficult to say, from the code I can see there is no problem, can you post all the code from worker and subworker (h and c files), I think the issue will become clearer then!

      Alternatively, you could go back a step and forget the thread for now, just create two objects (worker and subworker) connected a signal / slot one in each direction (as you have done) and try that.

      Make sure you declare the signals and the slots in the respective header files.

      Can you send multiple work() signals to the sub worker? - is it getting stuck?

      1 Reply Last reply
      0
      • S Offline
        S Offline
        SGaist
        Lifetime Qt Champion
        wrote on 7 Mar 2014, 20:36 last edited by
        #3

        Hi,

        is subWorkerObj a class member ? If not it will probably be destroyed before it does anything.

        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
        1
        • F Offline
          F Offline
          frankiefrank
          wrote on 8 Mar 2014, 16:48 last edited by
          #4

          I'll get some code here asap.

          @SGaist
          subWorkerObj is indeed a class member.

          "Roads? Where we're going, we don't need roads."

          1 Reply Last reply
          0
          • F Offline
            F Offline
            frankiefrank
            wrote on 8 Mar 2014, 17:03 last edited by
            #5

            I might have figured this out. My main application thread is starting my first worker thread but it has it's own loop in a run() method, without calling exec(). Would that mean that for this worker thread there's no event loop to process incoming signals?

            "Roads? Where we're going, we don't need roads."

            1 Reply Last reply
            0
            • S Offline
              S Offline
              SGaist
              Lifetime Qt Champion
              wrote on 8 Mar 2014, 21:31 last edited by
              #6

              I'm not sure I am following you correctly, can you show the related code ?

              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
              • F Offline
                F Offline
                frankiefrank
                wrote on 9 Mar 2014, 16:08 last edited by
                #7

                I've created a project on the side with the same setup to reproduce the problem.

                It's based off the basic "new Widget Application". In the MainWindow I have a WorkerObjHost running in its own thread, it is creating the WorkerObj running in its own thread, which in turn creates the SubWorker in its own (third thread). The issue is with the connection between Worker and SubWorker.

                Edit: the code here is deemed too complex and lacking event loops to actually process the slots, any late-comers to the thread, please don't spend too much time figuring it out.
                Code:
                MainWindow.h
                @
                // Created this pushButton to start things off
                public slots:
                void on_pushButton_clicked();

                private:
                Ui::MainWindow *ui;
                WorkerObjHost *workerObjHost;
                @

                In MainWindow.cpp
                @
                MainWindow::MainWindow(QWidget *parent) :
                QMainWindow(parent),
                ui(new Ui::MainWindow)
                {
                ui->setupUi(this);
                workerObjHost = new WorkerObjHost(this);
                }

                void MainWindow::on_pushButton_clicked()
                {
                workerObjHost->start();
                }
                @

                WorkerObjHost.h
                @
                #ifndef WORKEROBJHOST_H
                #define WORKEROBJHOST_H

                #include <QThread>
                class WorkerObjHost : public QThread
                {
                public:
                WorkerObjHost(QObject *parent = NULL);
                virtual void run();
                };

                #endif // WORKEROBJHOST_H
                @

                WorkerObjHost.cpp
                @
                #include "workerobjhost.h"
                #include "workerobj.h"

                WorkerObjHost::WorkerObjHost(QObject *parent)
                : QThread(parent)
                {
                }

                void WorkerObjHost::run()
                {
                // not parented here, but seems it doesn't affect outcome
                WorkerObj *worker = new WorkerObj;
                worker->start();

                while (true) {
                // Do some work
                }
                }
                @

                WorkerObj.h
                @
                #ifndef WORKEROBJ_H
                #define WORKEROBJ_H

                #include <QThread>
                #include "subworkerobj.h"

                class WorkerObj : public QThread
                {
                Q_OBJECT

                public:
                WorkerObj(QObject *parent = NULL);

                signals:
                void work();

                public slots:
                void handleSignalFromSubWorker();

                protected:
                virtual void run();
                };

                #endif // WORKEROBJ_H
                @

                WorkerObj.cpp
                @
                #include "workerobj.h"
                #include "subworkerobj.h"

                WorkerObj::WorkerObj(QObject *parent)
                : QThread(parent)
                {
                }

                void WorkerObj::run()
                {
                SubWorkerObj subWorkerObj;
                QThread *subWorkerThread = new QThread;
                subWorkerObj.moveToThread(subWorkerThread);
                subWorkerThread->start();

                // Both connections return true
                bool ok = connect(this, SIGNAL(work()), &subWorkerObj, SLOT(beginWork()));
                ok = connect(&subWorkerObj, SIGNAL(signalFromSubWorker()), this, SLOT(handleSignalFromSubWorker()));

                emit work();

                while (true)
                {
                // do other things
                }
                }

                void WorkerObj::handleSignalFromSubWorker()
                {
                // This doesn't get called
                }
                @

                SubWorkerObj.h
                @
                #ifndef SUBWORKEROBJ_H
                #define SUBWORKEROBJ_H

                #include <QObject>

                class SubWorkerObj : public QObject
                {
                Q_OBJECT

                public:
                SubWorkerObj();

                signals:
                void signalFromSubWorker();

                public slots:
                void beginWork();
                };
                #endif // SUBWORKEROBJ_H
                @

                SubWorkerObj.cpp
                @
                #include "subworkerobj.h"

                SubWorkerObj::SubWorkerObj()
                {
                }

                void SubWorkerObj::beginWork()
                {
                emit signalFromSubWorker();
                }
                @

                "Roads? Where we're going, we don't need roads."

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on 9 Mar 2014, 20:19 last edited by
                  #8

                  You're making things overly complicated. You have three levels of thread and none of them has an active event loop. So signals and slots between them will not work as you think.

                  Have a look at the latest "QThread documentation":http://qt-project.org/doc/qt-5/qthread.html you'll see there how to implement the worker object paradigm

                  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
                  • F Offline
                    F Offline
                    frankiefrank
                    wrote on 10 Mar 2014, 09:09 last edited by
                    #9

                    Thanks SGaist. You have to guess the rest of the code from what I posted but it's built up that way for a reason (and of course, the original design didn't consider using signals and slots at that point). But I think I can make some changes and get an event loop running.

                    There's something I don't really understand. Is an event loop always necessary on the thread that is supposed to execute the connected slot? It seems that emitting the signal works even if I don't have an event loop, and if the connected slot is on the same thread it executes directly. So basically once I want cross thread signals and slots, I need an event loop on the thread with the slots?

                    "Roads? Where we're going, we don't need roads."

                    1 Reply Last reply
                    0
                    • JKSHJ Offline
                      JKSHJ Offline
                      JKSH
                      Moderators
                      wrote on 10 Mar 2014, 11:06 last edited by
                      #10

                      Hi,

                      [quote]Is an event loop always necessary on the thread that is supposed to execute the connected slot?[/quote]Yes.

                      [quote]It seems that emitting the signal works even if I don’t have an event loop,[/quote]You don't need an event loop to emit signals.

                      [quote]and if the connected slot is on the same thread it executes directly.[/quote]Yes, a "DirectConnection":http://qt-project.org/doc/qt-5/qt.html#ConnectionType-enum bypasses the event loop to make a direct function call.

                      [quote] So basically once I want cross thread signals and slots, I need an event loop on the thread with the slots?[/quote]Correct.

                      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                      1 Reply Last reply
                      0
                      • F Offline
                        F Offline
                        frankiefrank
                        wrote on 10 Mar 2014, 11:58 last edited by
                        #11

                        Ah thank you JKSH for clearing some of this out.

                        "Roads? Where we're going, we don't need roads."

                        1 Reply Last reply
                        0

                        1/11

                        7 Mar 2014, 17:26

                        • Login

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