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"
감사합니다! QtConcurrent :: run이 나를위한 옵션인지 아닌지는 지금 모르겠다. 지금은 알 수 없다.하지만 나는 그 개념을 이해한다고 생각한다. 이 경우 싱글 톤 문제는 무엇입니까? 그렇지 않으면 그 스레드와 통신 할 필요가있는 모든 클래스가 필요합니다. 꽤 복잡하게 들리는 객체에 대한 포인터를 알 수 있습니다. – honiahaka10
QStateMachine에 대해서는 개념을 이해하지 못했지만 작은 예제가 있습니까? ? 이해할 수있는 모든 가능한 신호에 대한 상태와 모든 클래스에 대한 결과 코드를 작성해야합니다. 나는 그들이 아직 처리되지 않았다는 것을 말하는 국가와 함께 초기화 할 것이다. 내 대기 절차에서 모든 상태가 유효한 상태가 될 때까지 모든 상태를 계속 점검 할 것입니다. 나는 그것을 정확하게 이해 했는가? – honiahaka10
우선 * 스레드가 있다고 가정합니다. 당신은 아마 그것에 신경 쓰지 않아도됩니다. 'QThreadPool'이 스레드를 가장 효율적으로 관리하게하고'QtConcurrent :: run'을 사용하여 작업을 제출하십시오. 컨트롤러 (비즈니스 논리)는 동시에 수행 할 작업을 제출하고 결과에 대해 작업하는 단일 'QObject'일 수 있습니다 (편집 참조). –