Qt Forum

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

    Unsolved Worker/Controller multi-threading and interface class

    General and Desktop
    3
    4
    119
    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.
    • F
      fryn3 last edited by fryn3

      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 Reply Quote 0
      • SGaist
        SGaist Lifetime Qt Champion last edited by

        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 Reply Quote 0
        • Kent-Dorfman
          Kent-Dorfman last edited by

          @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 Reply Quote 0
          • F
            fryn3 @Kent-Dorfman last edited by fryn3

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

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