2016-08-23 6 views
1

현재 여러 스레드 간의 통신을 위해 좋은 디자인의 Qt 디자인을 만들려고합니다. 적용 창을 클릭하면 다른 신호를 내 보냅니다. 예를 들어 하나는 SQL 연결을 만들고 다른 하나는 다른 것을 변경하는 것입니다. 다른 클래스의 백그라운드 스레드에서 환경 설정을 변경하고 변경 한 후에 결과 신호를 내 보냅니다. 환경 설정 창에서 창을 닫거나 오류 메시지를 인쇄하기 전에 모든 신호가 수신 될 때까지 기다리고 싶습니다 (참 또는 거짓 결과 포함).스레드 통신을위한 myDesign을 사용할 수 있습니까?

첨부 된 그림에 내 디자인을 그렸습니다. 그게 내 목적을위한 올바른 방법인가? 나는 현재 모든 결과를 기다리는 방법으로 고심하고있다. 모든 결과를 저장하고 모든 신호를 수신했는지 여부를 확인하기 위해 일종의 배열을 만들려고합니다. 하지만 꽤 못생긴 것 같습니다. 모든 신호가 수신 될 때까지 기다리는 것이 더 좋은 방법입니까?

또한 백그라운드 스레드의 클래스를 singelton으로 만드는 것이 좋습니다. 클래스의 인스턴스가 하나만 있으면 클래스에 대한 액세스가 매우 쉬울 것입니다. 모든 객체에 포인터를 드래그 할 필요가 없으므로 클래스를 알아야합니다.

또한 데이터베이스가 연결되어 있고 다른 스레드에서 직접 액세스하는지 여부를 알려주는 MySQL 클래스의 공용 멤버를 저장하는 것이 좋은지 알고 싶습니다.

감사합니다. 이 신호를 수신 할 때이 상태 사이를 전환 할 수 있습니다

enter image description here

답변

2

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" 
+0

감사합니다! QtConcurrent :: run이 나를위한 옵션인지 아닌지는 지금 모르겠다. 지금은 알 수 없다.하지만 나는 그 개념을 이해한다고 생각한다. 이 경우 싱글 톤 문제는 무엇입니까? 그렇지 않으면 그 스레드와 통신 할 필요가있는 모든 클래스가 필요합니다. 꽤 복잡하게 들리는 객체에 대한 포인터를 알 수 있습니다. – honiahaka10

+0

QStateMachine에 대해서는 개념을 이해하지 못했지만 작은 예제가 있습니까? ? 이해할 수있는 모든 가능한 신호에 대한 상태와 모든 클래스에 대한 결과 코드를 작성해야합니다. 나는 그들이 아직 처리되지 않았다는 것을 말하는 국가와 함께 초기화 할 것이다. 내 대기 절차에서 모든 상태가 유효한 상태가 될 때까지 모든 상태를 계속 점검 할 것입니다. 나는 그것을 정확하게 이해 했는가? – honiahaka10

+0

우선 * 스레드가 있다고 가정합니다. 당신은 아마 그것에 신경 쓰지 않아도됩니다. 'QThreadPool'이 스레드를 가장 효율적으로 관리하게하고'QtConcurrent :: run'을 사용하여 작업을 제출하십시오. 컨트롤러 (비즈니스 논리)는 동시에 수행 할 작업을 제출하고 결과에 대해 작업하는 단일 'QObject'일 수 있습니다 (편집 참조). –