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. Custom Type Sending Classes for communication between threads
Forum Updated to NodeBB v4.3 + New Features

Custom Type Sending Classes for communication between threads

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 3 Posters 1.4k 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.
  • H Offline
    H Offline
    Hubbard
    wrote on last edited by
    #1

    I am new to programming custom type sending signals into Qt and need help, I tried studying some of it but I have limited time and the situation of application is quite complex, essentially I have a central class storing data and other classes that is instanced at runtime by the user interfacing with MainWindow, also created in this moment is a thread that constantly gathers data from a microcontroller elsewhere in the world (outside of the thread, the code for this miraculously works fine). however, passing this data to the class from inside the thread has not happened, I used signals emitted by the thread to pass information to the QNetworkAccessManager of the class bound to the thread, with which it then communicates with the microcontroller, but no information or evidence that the slot is even executed is presented.

    MainWindow's dynamic connection of the worker's signals to the class

    connect(unitWorkerAddress[unitTotal], SIGNAL(finishedSignal(int)), this, SLOT(threadFinishSlot(int)));
    connect(unitWorkerAddress[unitTotal], SIGNAL(networkPostSignal(QNetworkRequest, QByteArray)),
    unitAddress[unitTotal], SLOT(threadNetworkPostSlot(QNetworkRequest request, QByteArray array)) );

    The slot in the class stored in the heap on the main thread

    void BioBloomUnit::threadNetworkPostSlot(QNetworkRequest inputRequest, QByteArray inputArray)
    {
    qDebug() << "13";

    qDebug() << inputArray.data();
    
    qDebug() << "14";
    
    unitNetworkManagerAddress->post(inputRequest, inputArray);
    
    qDebug() << "threadNetworkPressSlot finished";
    

    }

    On a worker bound to that class and created alongside it doing some processes and emitting signal to some of the classes slots from an alternate thread

    emit networkPostSignal(request, postData);
    
    A 1 Reply Last reply
    0
    • H Hubbard

      I am new to programming custom type sending signals into Qt and need help, I tried studying some of it but I have limited time and the situation of application is quite complex, essentially I have a central class storing data and other classes that is instanced at runtime by the user interfacing with MainWindow, also created in this moment is a thread that constantly gathers data from a microcontroller elsewhere in the world (outside of the thread, the code for this miraculously works fine). however, passing this data to the class from inside the thread has not happened, I used signals emitted by the thread to pass information to the QNetworkAccessManager of the class bound to the thread, with which it then communicates with the microcontroller, but no information or evidence that the slot is even executed is presented.

      MainWindow's dynamic connection of the worker's signals to the class

      connect(unitWorkerAddress[unitTotal], SIGNAL(finishedSignal(int)), this, SLOT(threadFinishSlot(int)));
      connect(unitWorkerAddress[unitTotal], SIGNAL(networkPostSignal(QNetworkRequest, QByteArray)),
      unitAddress[unitTotal], SLOT(threadNetworkPostSlot(QNetworkRequest request, QByteArray array)) );

      The slot in the class stored in the heap on the main thread

      void BioBloomUnit::threadNetworkPostSlot(QNetworkRequest inputRequest, QByteArray inputArray)
      {
      qDebug() << "13";

      qDebug() << inputArray.data();
      
      qDebug() << "14";
      
      unitNetworkManagerAddress->post(inputRequest, inputArray);
      
      qDebug() << "threadNetworkPressSlot finished";
      

      }

      On a worker bound to that class and created alongside it doing some processes and emitting signal to some of the classes slots from an alternate thread

      emit networkPostSignal(request, postData);
      
      A Offline
      A Offline
      ambershark
      wrote on last edited by ambershark
      #2

      @Hubbard I don't see any of the threading code in here so I can't comment on that. Here are some of my guesses...

      1. I am assuming you used moveToThread() for your threading. If not that can be the issue since you may or may not have a proper QEventLoop in your thread.

      2. Are you sure unitTotal is a valid value and you are getting the correct addresses that you expect for both unitAddress and unitWorkerAddress?

      3. Are none of your signals/slots working between your thread and mainwindow thread?

      4. If you run the program via the console Qt will output information when a signal/slot is not connected like you'd expect. Try running where you can see the console output. It is possible you are not hooking up the signals and slots like you think you are.

      Beyond that, if you could show some more code where the signals are connected in your MainWindow, how your thread is created (probably near the signal connections), and the actual thread implementation. With that information I may see something that is mapped wrong.

      My L-GPL'd C++ Logger github.com/ambershark-mike/sharklog

      1 Reply Last reply
      0
      • H Offline
        H Offline
        Hubbard
        wrote on last edited by
        #3

        I know these things and there isn't a slot warning and the qDebugs don't come out

        unitAddress.append(new BioBloomUnit(this));                                                                                                            //Instance a new unit class
        unitAddress[unitTotal]->setUnitNumber(unitTotal);
        unitAddress[unitTotal]->setMacAddress("2C:3A:E8:37:D8:6A");
        
        ribbonAddress.append(new UnitRibbon(unitAddress[unitTotal], this));                                                                                    //Instance a new unit ribbon class
        ribbonAddress[unitTotal]->setRibbonNumber(unitTotal);
        
        itemAddress.append(new QListWidgetItem(ui->UnitList));                                                                                                 //Instance a new list widget item
        
        itemAddress[unitTotal]->setSizeHint(ribbonAddress[unitTotal]->size());                                                                                 //Let list widget item know about size of unit ribbon
        ui->UnitList->setItemWidget(itemAddress[unitTotal], ribbonAddress[unitTotal]);                                                                        //Set the unit ribbon in the list widget item
        ui->UnitList->addItem(itemAddress[unitTotal]);                                                                                                       //Add the item to the list
        
        connect(ribbonAddress[unitTotal]->ui->RibbonButton, SIGNAL(released()), unitAddress[unitTotal], SLOT(unitRibbonPressSlot()) );                          //Connect the unit ribbon button to the unitRibbonPressSlot of the unit class
        connect(ribbonAddress[unitTotal]->ui->ConfigureButton, SIGNAL(released()), unitAddress[unitTotal], SLOT(unitRibbonConfigureButtonPressSlot()) );       //Connect the unit ribbon's configure button to the unitRibbonConfigureButtonPressSlot of the unit class
        
        unitAddress[unitTotal]->setPlantProfileTemplate(unitAddress[unitTotal]->configureWindowAddress->plantProfile[0]);
        
        ribbonAddress[unitTotal]->updateData();
        
        unitWorkerAddress.append(new UnitWorker(unitAddress[unitTotal]));                                                                       //Instance a new worker for the unit
        unitThreadAddress.append(new QThread);                                                                                                 //Instance a new thread for the worker
        
        unitWorkerAddress[unitTotal]->moveToThread(unitThreadAddress[unitTotal]);                                                               //Move the unit's worker to the unit's thread
        
        connect(unitWorkerAddress[unitTotal], SIGNAL(error(QString)), this, SLOT(errorString(QString)));
        connect(unitThreadAddress[unitTotal], SIGNAL(started()), unitWorkerAddress[unitTotal], SLOT(process()));
        //connect(unitWorkerAddress[unitTotal], SIGNAL(finished()), unitThreadAddress[unitTotal], SLOT(quit()));
        //connect(unitWorkerAddress[unitTotal], SIGNAL(finished()), unitWorkerAddress[unitTotal], SLOT(deleteLater()));
        //connect(unitThreadAddress[unitTotal], SIGNAL(finished()), unitThreadAddress[unitTotal], SLOT(deleteLater()));
        
        qDebug() << "1";
        
        connect(unitWorkerAddress[unitTotal], SIGNAL(finishedSignal(int)), this, SLOT(threadFinishSlot(int)));
        connect(unitWorkerAddress[unitTotal], SIGNAL(networkPostSignal(QNetworkRequest, QByteArray)), unitAddress[unitTotal], SLOT(threadNetworkPostSlot(QNetworkRequest request, QByteArray array)) );
        
        unitThreadAddress[unitTotal]->start();
        
        qDebug() << "2";
        
        unitTotal += 1;                                                                                                                                         //Increment the number of units on the system by 1
        

        }

        its a code designed to allow a user to create as many instances of biobloomunit as they need, and having biobloomunit still maintaining contact with its respective microcontroller

        A 1 Reply Last reply
        0
        • H Hubbard

          I know these things and there isn't a slot warning and the qDebugs don't come out

          unitAddress.append(new BioBloomUnit(this));                                                                                                            //Instance a new unit class
          unitAddress[unitTotal]->setUnitNumber(unitTotal);
          unitAddress[unitTotal]->setMacAddress("2C:3A:E8:37:D8:6A");
          
          ribbonAddress.append(new UnitRibbon(unitAddress[unitTotal], this));                                                                                    //Instance a new unit ribbon class
          ribbonAddress[unitTotal]->setRibbonNumber(unitTotal);
          
          itemAddress.append(new QListWidgetItem(ui->UnitList));                                                                                                 //Instance a new list widget item
          
          itemAddress[unitTotal]->setSizeHint(ribbonAddress[unitTotal]->size());                                                                                 //Let list widget item know about size of unit ribbon
          ui->UnitList->setItemWidget(itemAddress[unitTotal], ribbonAddress[unitTotal]);                                                                        //Set the unit ribbon in the list widget item
          ui->UnitList->addItem(itemAddress[unitTotal]);                                                                                                       //Add the item to the list
          
          connect(ribbonAddress[unitTotal]->ui->RibbonButton, SIGNAL(released()), unitAddress[unitTotal], SLOT(unitRibbonPressSlot()) );                          //Connect the unit ribbon button to the unitRibbonPressSlot of the unit class
          connect(ribbonAddress[unitTotal]->ui->ConfigureButton, SIGNAL(released()), unitAddress[unitTotal], SLOT(unitRibbonConfigureButtonPressSlot()) );       //Connect the unit ribbon's configure button to the unitRibbonConfigureButtonPressSlot of the unit class
          
          unitAddress[unitTotal]->setPlantProfileTemplate(unitAddress[unitTotal]->configureWindowAddress->plantProfile[0]);
          
          ribbonAddress[unitTotal]->updateData();
          
          unitWorkerAddress.append(new UnitWorker(unitAddress[unitTotal]));                                                                       //Instance a new worker for the unit
          unitThreadAddress.append(new QThread);                                                                                                 //Instance a new thread for the worker
          
          unitWorkerAddress[unitTotal]->moveToThread(unitThreadAddress[unitTotal]);                                                               //Move the unit's worker to the unit's thread
          
          connect(unitWorkerAddress[unitTotal], SIGNAL(error(QString)), this, SLOT(errorString(QString)));
          connect(unitThreadAddress[unitTotal], SIGNAL(started()), unitWorkerAddress[unitTotal], SLOT(process()));
          //connect(unitWorkerAddress[unitTotal], SIGNAL(finished()), unitThreadAddress[unitTotal], SLOT(quit()));
          //connect(unitWorkerAddress[unitTotal], SIGNAL(finished()), unitWorkerAddress[unitTotal], SLOT(deleteLater()));
          //connect(unitThreadAddress[unitTotal], SIGNAL(finished()), unitThreadAddress[unitTotal], SLOT(deleteLater()));
          
          qDebug() << "1";
          
          connect(unitWorkerAddress[unitTotal], SIGNAL(finishedSignal(int)), this, SLOT(threadFinishSlot(int)));
          connect(unitWorkerAddress[unitTotal], SIGNAL(networkPostSignal(QNetworkRequest, QByteArray)), unitAddress[unitTotal], SLOT(threadNetworkPostSlot(QNetworkRequest request, QByteArray array)) );
          
          unitThreadAddress[unitTotal]->start();
          
          qDebug() << "2";
          
          unitTotal += 1;                                                                                                                                         //Increment the number of units on the system by 1
          

          }

          its a code designed to allow a user to create as many instances of biobloomunit as they need, and having biobloomunit still maintaining contact with its respective microcontroller

          A Offline
          A Offline
          ambershark
          wrote on last edited by
          #4

          @Hubbard Hmm, I'm assuming you are using a QueuedConnection for your signals. Is your main thread blocked somewhere or is it getting back to it's event loop? If the signal is emitted in your worker thread your main thread can't process it until flow returns to the QEventLoop. This works the same for the main thread event -> worker thread.

          Are both in their event loops (not blocked on some call in a slot somewhere)?

          I don't see anything that jumps out as wrong with the code, but without being able to see the bigger picture it's pretty tough to diagnose. Threading is complicated. Solving problems in threading can be one of the hardest things. Not being able to see the thread functions or the code just makes it that much harder. So I'm just throwing out some guesses here.

          If all else fails I can write up a quick example showing what you are trying to accomplish and maybe that can help you figure out where your code/events are wrong. I prefer we try other things first though so I don't need to spend an hour writing proof of concept code. :)

          My L-GPL'd C++ Logger github.com/ambershark-mike/sharklog

          H 1 Reply Last reply
          0
          • A ambershark

            @Hubbard Hmm, I'm assuming you are using a QueuedConnection for your signals. Is your main thread blocked somewhere or is it getting back to it's event loop? If the signal is emitted in your worker thread your main thread can't process it until flow returns to the QEventLoop. This works the same for the main thread event -> worker thread.

            Are both in their event loops (not blocked on some call in a slot somewhere)?

            I don't see anything that jumps out as wrong with the code, but without being able to see the bigger picture it's pretty tough to diagnose. Threading is complicated. Solving problems in threading can be one of the hardest things. Not being able to see the thread functions or the code just makes it that much harder. So I'm just throwing out some guesses here.

            If all else fails I can write up a quick example showing what you are trying to accomplish and maybe that can help you figure out where your code/events are wrong. I prefer we try other things first though so I don't need to spend an hour writing proof of concept code. :)

            H Offline
            H Offline
            Hubbard
            wrote on last edited by
            #5

            @ambershark Please do, just the NetworkAccessManager part, I can't create heap allocations for the threads own one yet can't 'borrow' it from its owner unit

            A 1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6

              Hi,

              Out of curiosity, why are you sending a QNetworkRequest with a separate payload to your threadNetworkPostSlot ? From the looks of it, it seems that you should send the details like the address of the device and the payload and let that other class manage whatever is needed to send the request you want.

              That way you avoid putting too much knowledge of the network interaction in you unit address widget.

              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
              2
              • H Hubbard

                @ambershark Please do, just the NetworkAccessManager part, I can't create heap allocations for the threads own one yet can't 'borrow' it from its owner unit

                A Offline
                A Offline
                ambershark
                wrote on last edited by ambershark
                #7

                @Hubbard Ok here you go. This doesn't use sockets as I figured that was overkill for a simple example on threaded signaling between custom components.

                CMakeLists.txt -- this is the build, feel free to adapt to qmake if that if what you prefer:

                cmake_minimum_required(VERSION 3.8)
                project(threadexample)
                
                set(CMAKE_CXX_STANDARD 11)
                set(CMAKE_AUTOMOC ON)
                
                find_package(Qt5 COMPONENTS Core Widgets Gui REQUIRED)
                
                set(SOURCE_FILES main.cpp MainWindow.cpp MainWindow.h Worker.cpp Worker.h)
                add_executable(threadexample ${SOURCE_FILES})
                qt5_use_modules(${PROJECT_NAME} Core Widgets Gui)
                

                main.cpp

                #include <QApplication>
                #include "MainWindow.h"
                
                int main(int ac, char **av)
                {
                        QApplication app(ac, av);
                        MainWindow mw;
                        mw.show();
                        return app.exec();
                }
                

                MainWindow.h

                #pragma once
                
                #include <QMainWindow>
                
                class QScrollArea;
                
                class MainWindow : public QMainWindow
                {
                        Q_OBJECT
                
                public:
                        MainWindow(QWidget *parent=nullptr);
                
                private slots:
                        void clickMeClicked();
                
                private:
                        QScrollArea *sa_;
                };
                

                MainWindow.cpp:

                #include "MainWindow.h"
                #include "Worker.h"
                #include <QVBoxLayout>
                #include <QScrollArea>
                #include <QPushButton>
                #include <QDebug>
                #include <QThread>
                #include <QLabel>
                
                MainWindow::MainWindow(QWidget *parent)
                : QMainWindow(parent)
                {
                        sa_ = new QScrollArea();
                        sa_->setLayout(new QVBoxLayout());
                
                        auto *cw = new QWidget();
                        auto *layout = new QVBoxLayout();
                        auto *clickMe = new QPushButton("Click Me");
                        connect(clickMe, &QPushButton::clicked, this, &MainWindow::clickMeClicked);
                
                        layout->addWidget(sa_);
                        layout->addWidget(clickMe);
                        cw->setLayout(layout);
                        setCentralWidget(cw);
                
                        resize(600, 400);
                        qDebug() << QThread::currentThreadId() << "- main thread";
                }
                
                void MainWindow::clickMeClicked()
                {
                        // add a layout to our scrollarea.. this emulate the BioBloom control since I have no idea what that is
                        auto *label = new QLabel("XXX");
                        sa_->layout()->addWidget(label);
                
                        // create a thread for our worker
                        // NOTE: I am leaking memory here, but this is just for example purposes, make sure to clean your memory
                        // by attaching an exit condition to the thread and handling the finished() signal with a deleteLater().
                        auto *thread = new QThread();
                        auto *worker = new Worker();
                        worker->moveToThread(thread);
                        connect(thread, SIGNAL(started()), worker, SLOT(process()));
                        connect(worker, SIGNAL(update(int)), label, SLOT(setNum(int)));
                        thread->start();
                }
                

                Worker.h

                #pragma once
                
                #include <QObject>
                
                class Worker : public QObject
                {
                        Q_OBJECT
                
                public:
                        Worker(QObject *parent=nullptr);
                
                public slots:
                        void process();
                        void ding();
                
                signals:
                        void finished();
                        void update(int);
                
                private:
                        unsigned int currentTick_;
                };
                

                Worker.cpp

                #include <QTimer>
                #include <QThread>
                #include <QDebug>
                #include "Worker.h"
                
                Worker::Worker(QObject *parent) : QObject(parent), currentTick_(0)
                {
                }
                
                void Worker::process()
                {
                        // start a timer that kicks off a signal on our thread every 1 second
                        // this will simulate a network event since I'm not spending the time
                        // to add networking to this just as a test example
                        auto *timer = new QTimer(this);
                        connect(timer, SIGNAL(timeout()), this, SLOT(ding()));
                        timer->start(1000);
                }
                
                void Worker::ding()
                {
                        qDebug() << QThread::currentThreadId() << "- ding";
                        emit update(currentTick_++);
                }
                

                And finally, here is a screenshot of it running so you can see all the different threads updating the main gui thread objects:

                0_1520143731455_threadexample.png

                My L-GPL'd C++ Logger github.com/ambershark-mike/sharklog

                1 Reply Last reply
                3

                • Login

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