c++ - 线程通信的 myDesign 是否可以接受?

标签 c++ multithreading qt communication signals-slots

我目前正在尝试为多个线程之间的通信创建一个良好且有效的 Qt 设计。我有一个首选项窗口,它会在单击“应用”时发出不同的信号。例如,一个用于创建 SQL 连接,一个用于更改其他内容。我想更改不同类的后台线程中的首选项,并且在进行更改后它们将发出结果信号。在我的首选项窗口中,我现在想等到所有信号都收到(无论结果是真还是假),然后再关闭窗口或打印错误消息。

我试着在附图中画出我的设计。这是我的目的的正确方法吗?我目前正在为等待所有结果的方式而苦苦挣扎。我正在考虑创建某种数组来保存每个结果并检查数组,是否收到所有信号。但这听起来很难看……有没有更好的方法来等待所有信号都被接收到?

另外,将后台线程中的类作为 singelton 是个好主意吗?我只需要一个类的实例,这将使对类的访问变得非常容易,因为我不需要将指针拖到每个需要知道类的对象。

我还想知道,在 MySQL 类中存储一个公共(public)成员是否是个好主意,它告诉我数据库是否已连接并直接从其他线程访问它?

谢谢!

enter image description here

最佳答案

QStateMachine 将完全按照您的意愿行事:它可以在接收到信号时在状态之间转换。

后台线程可能不需要基于类,而且无论如何它们绝对不应该是单例的。您很可能可以为 QtConcurrent::run 提供一个仿函数,并在那里发出信号。

逻辑应该分解成一个单独的QObject:

// https://github.com/KubaO/stackoverflown/tree/master/questions/thread-jobs-39109247
#include <QtWidgets>
#include <QtConcurrent>
#include <functional>

class Controller : public QObject {
    Q_OBJECT
    QStateMachine m_machine{this};
    QState s_init{&m_machine};
    QState s_busy{&m_machine};
    QState s_idle{&m_machine};
    int m_activeTasks = 0;
    void onTaskStarted() {
        ++ m_activeTasks;
        emit taskRunning();
    }
    void onTaskDone() {
        if (--m_activeTasks == 0) emit allTasksDone();
    }
    Q_SIGNAL void taskRunning();
    Q_SIGNAL void allTasksDone();
    Q_SIGNAL void task1Done(int result);
    Q_SIGNAL void task2Done(int result);
public:
    Q_SIGNAL void active();
    Q_SIGNAL void finished();
    Q_SLOT void doTask1() {
        onTaskStarted();
        QtConcurrent::run([this]{
            QThread::sleep(2); // pretend we do some work
            emit task1Done(42);
        });
    }
    Q_SLOT void doTask2() {
        onTaskStarted();
        QtConcurrent::run([this]{
            QThread::sleep(5); // pretend we do some work
            emit task2Done(44);
        });
    }
    Controller(QObject * parent = nullptr) :
        QObject{parent}
    {
        // This describes the state machine
        s_init.addTransition(this, &Controller::taskRunning, &s_busy);
        s_idle.addTransition(this, &Controller::taskRunning, &s_busy);
        s_busy.addTransition(this, &Controller::allTasksDone, &s_idle);
        m_machine.setInitialState(&s_init);
        m_machine.start();
        //
        connect(this, &Controller::task1Done, this, [this](int result){
            onTaskDone();
            qDebug() << "task 1 is done with result" << result;
        });
        connect(this, &Controller::task2Done, this, [this](int result){
            onTaskDone();
            qDebug() << "task 2 is done with result" << result;
        });
        connect(&s_busy, &QState::entered, this, &Controller::active);
        connect(&s_idle, &QState::entered, this, &Controller::finished);
    }
};

Q_GLOBAL_STATIC(QStringListModel, model)
int main(int argc, char ** argv) {
    using Q = QObject;
    QApplication app{argc, argv};
    Controller ctl;
    QWidget w;
    QFormLayout layout{&w};
    QPushButton start1{"Start Task 1"};
    QPushButton start2{"Start Task 2"};
    QListView log;
    layout.addRow(&start1);
    layout.addRow(&start2);
    layout.addRow(&log);
    Q::connect(&start1, &QPushButton::clicked, &ctl, &Controller::doTask1);
    Q::connect(&start2, &QPushButton::clicked, &ctl, &Controller::doTask2);
    Q::connect(&ctl, &Controller::active, []{ qDebug() << "Active"; });
    Q::connect(&ctl, &Controller::finished, []{ qDebug() << "Finished"; });

    log.setModel(model);
    qInstallMessageHandler(+[](QtMsgType, const QMessageLogContext &, const QString & msg){
        auto row = model->rowCount();
        model->insertRow(row);
        model->setData(model->index(row), msg);
    });
    w.show();
    return app.exec();
}
#include "main.moc"

关于c++ - 线程通信的 myDesign 是否可以接受?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39109247/

相关文章:

c++ - 当列表中有两个以上的项目时,链表的函数添加会崩溃?

Qt 类层次结构图像/pdf

c++ - 通用项目的 Qt Creator c++11 语法突出显示

c++ - Qt; QWidget 移除和删除。 setParent(NULL) 有必要吗?

c++ - 使用 gSOAP 以本地时间而不是 UTC 返回日期时间

c++ - resolve_initial_references 导致 SystemException

C++ 4 字节对齐数据

python - 为什么多重处理没有使用我所有的核心

c# - UI 线程正在阻止调用 COM 对象的后台线程

ios - Swift 4 中的核心数据并发问题