Unsolved Worker/Controller multi-threading and interface class
-
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"; });
- Do I reinvent the wheel?
- Why is the
Controller::finished
signal not emitted when the object is deleted (when the window is closed)? - Is it possible to make signals private not to create a
Private Controller
? - Do I need to make the controller a descendant of
IClass
? - 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
. -
Hi,
Unless I missed it, you don't emit the finished signal anywhere.
-
@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.
-
@kent-dorfman I tried. The lambda is not executed.