【问题标题】:Worker/Controller multi-threading and interface classWorker/Controller 多线程和接口类
【发布时间】:2019-08-30 15:07:24
【问题描述】:

在我看来是多线程对象的接口类。当窗口关闭时,除了这一行之外,一切正常。

connect(_controller, &IClass::finished, this, [] { qDebug() << "finished"; });
  1. 我要重新发明轮子吗?
  2. 为什么在删除对象时(关闭窗口时)没有发出Controller::finished 信号?
  3. 是否可以将信号设为私有而不创建Private Controller
  4. 是否需要将控制器设为IClass 的后代?
  5. 提示和建议

代码示例:

主窗口.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

主窗口.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(); }

输出:

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

不要发出finished

【问题讨论】:

  • 也许我忽略了它,你在哪里“转发”并从你的 IClass 发出 finished() 信号?

标签: c++ multithreading qt interface qthread


【解决方案1】:

关于问题 #2:尝试对您的 main 进行此编辑:

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    int r = a.exec();

    qDebug() << "event loop gone ...";

    return r;
}

现在检查您的输出。如您所见,当finished 信号发出时,您的主线程不再有事件循环,因此不会捕获信号(因为它来自另一个线程)。

为了进一步证明这一点,在窗口中添加一个按钮并有一个clicked 槽,如下所示:

void MainWindow::on_pushButton_clicked()
{
    _controller->stop();
    qApp->processEvents();
    qApp->exit();
}

这样你退出应用程序,但只有在所有排队的事件都得到处理之后(即排队的信号被传递......)。

坦率地说,关于您提出的所有其他问题:即使对于一个赏金问题,它似乎也相当广泛。无论如何,希望我能有所帮助。

【讨论】:

  • call on_pushButton_clicked 这样工作,但我不明白,为什么Controller::~Controller() { _signals.callStop(); QCoreApplication::processEvents(); } 不工作。为什么主线程没有事件循环,如果我只调用析构函数MainWindow,而不是qApp-&gt;exit();。为什么析构函数完成了,不执行processEvent
  • 当析构函数被调用时,事件循环已经过去了,随后对 processEvents 的调用也没有任何意义了。每当您关闭(甚至隐藏)qt 应用程序中的 last 顶级小部件时,事件循环都会自动停止,而无需调用 exit。请记住,当MainWindow 实例超出范围时,即退出main 函数块时,MainWindow 析构函数在 Qapplication::exec 返回后被调用。
猜你喜欢
  • 2013-08-22
  • 2017-04-02
  • 1970-01-01
  • 1970-01-01
  • 2020-06-01
  • 2021-04-22
  • 1970-01-01
  • 1970-01-01
  • 2020-08-14
相关资源
最近更新 更多