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. Worker/Controller multi-threading and interface class

Worker/Controller multi-threading and interface class

Scheduled Pinned Locked Moved Unsolved General and Desktop
4 Posts 3 Posters 285 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.
  • F Offline
    F Offline
    fryn3
    wrote on last edited by fryn3
    #1

    Implemented as it seems to me an interface class for multithreaded objects. Everything works, except this line, when the window is closed.

    connect(_controller, &IClass::finished, this, [] { qDebug() << "finished"; });
    
    1. Do I reinvent the wheel?
    2. Why is the Controller::finished signal not emitted when the object is deleted (when the window is closed)?
    3. Is it possible to make signals private not to create a Private Controller?
    4. Do I need to make the controller a descendant of IClass?
    5. Tips and suggestions

    code example:
    #mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QDebug>
    #include <QMainWindow>
    #include <QThread>
    class Worker1;
    class Worker2;
    
    
    class IClass : public QObject{
        Q_OBJECT
    protected:
        IClass(QObject *parent = nullptr) : QObject(parent) { }
    public:
        enum class Types { Worker1, Worker2, };
        static IClass* CreateInstance(Types t, QObject *parent = nullptr);
    signals:
        void started();
        void finished();
    public slots:
        virtual void f1() = 0;
        virtual void f2(int i) = 0;
        virtual void f3(int x, double y) = 0;
        virtual void start() = 0;
        virtual void stop() = 0;
    };
    
    class PrivateController : public QObject {
        Q_OBJECT
        IClass *_w;
    public:
        PrivateController(IClass *c, QObject *parent = nullptr) : QObject(parent), _w(c) {
            connect(this, &PrivateController::f1, _w, &IClass::f1);
            connect(this, &PrivateController::f2, _w, &IClass::f2);
            connect(this, &PrivateController::f3, _w, &IClass::f3);
            connect(this, &PrivateController::stop, _w, &IClass::stop);
        }
        ~PrivateController() override;
        void callF1()                   { emit f1(); }
        void callF2(int i)              { emit f2(i); }
        void callF3(int x, double y)    { emit f3(x, y); }
        void callStop()                 { emit stop(); }
    signals:
        void f1();
        void f2(int i);
        void f3(int x, double y);
    
        
        void stop();
    };
    
    class Controller : public IClass {
        Q_OBJECT
    public:
        Controller(IClass::Types t, QObject *parent = nullptr)
                            : IClass(parent), _w(CreateInstance(t)), _signals(_w) {
            connect(_w, &IClass::started, this, &IClass::started);
            connect(_w, &IClass::finished, this, &IClass::finished);
        }
        ~Controller() override;
    public slots:
        void f1() override                  { _signals.f1(); }
        void f2(int i) override             { _signals.f2(i); }
        void f3(int x, double y) override   { _signals.f3(x, y); }
        void start() override {
            QThread *th = new QThread;
            _w->moveToThread(th);
            connect(th, &QThread::started, _w, &IClass::start);
            connect(_w, &IClass::finished, th, &QThread::quit);
            connect(_w, &IClass::finished, th, &QThread::deleteLater);
            connect(_w, &IClass::finished, _w, &IClass::deleteLater);
            th->start();
            qDebug() << "Controller::start";
        }
        void stop() override {
            _signals.stop();
            qDebug() << "Controller::stop";
        }
    protected:
        IClass *_w;
        PrivateController _signals;
    };
    
    class Worker1 : public IClass {
        Q_OBJECT
    public:
        Worker1(QObject *parent = nullptr)
                            : IClass(parent) {
            // some code
        }
    public slots:
        void f1() override {
            qDebug() << "Worker1::f1";
        }
        void f2(int i) override {
            qDebug() << "Worker1::f2" << i;
        }
        void f3(int x, double y) override {
            qDebug() << "Worker1::f3" << x << y;
        }
        void start() override {
            emit started();
            qDebug() << "Worker1::start";
        }
        void stop() override {
            emit finished();
            qDebug() << "Worker1::stop";
        }
    protected:
        // some code
    };
    
    class Worker2 : public IClass {
        Q_OBJECT
    public:
        Worker2(QObject *parent = nullptr)
                            : IClass(parent) {
            // some code
        }
    public slots:
        void f1() override {
            qDebug() << "Worker2::f1";
        }
        void f2(int i) override {
            qDebug() << "Worker2::f2" << i;
        }
        void f3(int x, double y) override {
            qDebug() << "Worker2::f3" << x << y;
        }
        void start() override {
            emit started();
            qDebug() << "Worker2::start";
        }
        void stop() override {
            emit finished();
            qDebug() << "Worker2::stop";
        }
    protected:
        // some code
    };
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
        IClass *_controller;
    };
    
    #endif // MAINWINDOW_H
    

    #mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow),
        _controller(new Controller(IClass::Types::Worker2, this))
    {
        ui->setupUi(this);
        connect(_controller, &IClass::started, this, [] { qDebug() << "started"; });
        connect(_controller, &IClass::finished, this, [] { qDebug() << "finished"; });
        _controller->start();
        _controller->f1();
        _controller->f2(2);
        _controller->f3(3, 4.4);
    //    _controller->stop();
    }
    
    MainWindow::~MainWindow() { delete ui; }
    
    PrivateController::~PrivateController() { qDebug() << "~PrivateController()"; }
    
    IClass *IClass::CreateInstance(IClass::Types t, QObject *parent) {
        switch(t) {
        case Types::Worker1: { return new Worker1(parent); }
        case Types::Worker2: { return new Worker2(parent); }
        }
    }
    
    Controller::~Controller() { _signals.callStop(); }
    

    OUTPUT:

    Controller::start
    Worker2::start
    Worker2::f1
    Worker2::f2 2
    Worker2::f3 3 4.4
    started
    ~PrivateController()
    Worker2::stop
    

    Don't emited finished.

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

      Hi,

      Unless I missed it, you don't emit the finished signal anywhere.

      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
      • Kent-DorfmanK Offline
        Kent-DorfmanK Offline
        Kent-Dorfman
        wrote on last edited by
        #3

        @fryn3 said in Worker/Controller multi-threading and interface class:

        connect(_controller, &IClass::finished, this, [] { qDebug() << "finished"; });

        what @SGaist said, but also...my line of thinking would be to test that the lambda is ever executed. during testing my initial lambda body would be { assert(0); }

        That way you'll know for sure if the lambda is ever executed.

        F 1 Reply Last reply
        0
        • Kent-DorfmanK Kent-Dorfman

          @fryn3 said in Worker/Controller multi-threading and interface class:

          connect(_controller, &IClass::finished, this, [] { qDebug() << "finished"; });

          what @SGaist said, but also...my line of thinking would be to test that the lambda is ever executed. during testing my initial lambda body would be { assert(0); }

          That way you'll know for sure if the lambda is ever executed.

          F Offline
          F Offline
          fryn3
          wrote on last edited by fryn3
          #4

          @kent-dorfman I tried. The lambda is not executed.

          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