简体   繁体   English

myDesign用于线程通信是否可以接受?

[英]Is myDesign for thread communication acceptable?

I am currently trying to create a good and working Qt design for communication between several threads. 我目前正在尝试为多个线程之间的通信创建一个良好且有效的Qt设计。 I have a preference window, which emits different signals up on clicking on apply. 我有一个首选项窗口,单击“应用”后会发出不同的信号。 For example one for creating the SQL connection and one changing other stuff. 例如,一个用于创建SQL连接,另一个用于更改其他内容。 I want to change the preferences in a background thread in different classes and after making the changes they shall emit a result signal. 我想在不同类的后台线程中更改首选项,并在进行更改后将发出结果信号。 In my preferences window I now want to wait until all signals are received (either with a true or a false result) before I either close the window or print an error message. 在我的“首选项”窗口中,我现在要等待,直到接收到所有信号(结果为真或假),然后再关闭窗口或打印错误消息。

I tried to draw my design in the attached picture. 我试图在附图中画出我的设计。 Is that the correct way for my purpose? 那是我目的的正确方法吗? I am currently struggling with the way of waiting for all results. 我目前正在努力等待所有结果。 I was thinking of creating some kind of array to save every result and check the array, whether all signals are received. 我正在考虑创建某种数组以保存每个结果并检查该数组是否接收到所有信号。 But that sounds pretty ugly... Is there a better method to wait until all signals are received? 但这听起来很难看……是否有更好的方法来等待接收到所有信号?

Also is it a good idea to make the classes in the background thread as a singelton ? 将后台线程中的类设为singelton也是一个好主意吗? I only need one instance of the classes and that would make the access to the classes pretty easy since I do not need to drag the pointers to every object, which needs to know the classes. 我只需要一个类的实例,这将使对类的访问变得非常容易,因为我不需要将指针拖到需要了解类的每个对象上。

Also i would like to know, whether it is a good Idea to store a public member in the MySQL Class, which tells me, whether the Database is connected and access it directly out of other threads? 我也想知道,在MySQL类中存储一个公共成员是否是一个好主意,这告诉我数据库是否已连接并直接从其他线程访问它?

Thank you! 谢谢!

在此处输入图片说明

The QStateMachine will do exactly what you want: it can transition between states when it receives signals. QStateMachine将完全按照您的要求进行操作:当它收到信号时,它可以在状态之间转换。

The background threads might not need to be based on classes, and no matter what they definitely shouldn't be singletons. 后台线程可能不必基于类,无论它们绝对不应该是单例。 Most likely you can give a functor to QtConcurrent::run , and emit the signal there. 您很可能可以将函子提供给QtConcurrent::run ,并在那里发出信号。

The logic should be factored out into a separate QObject : 逻辑应分解为单独的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"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM