2016-08-23 9 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», который представляет работу, которая должна выполняться одновременно, и действует на результаты, см. Редактирование. –