QThread在c ++中的基本用法

时间:2016-11-29 11:53:08

标签: c++ multithreading qt qthread

我有一个包含GUI的c ++代码,我需要在其中运行耗时的循环进行优化。

class OptimizationAlgorith(data *data);
{
private:
    var var1;
    var var2;
public:
    method1();
    method2();
    ..
    timeConsumingMethod(data);
}

需要在GUI类中调用,如下所示:

    class QRegistration: public QWidget
{
    Q_OBJECT
private:
    data *m_data;
    QPushButton     *m_button_run;
    OptimizationAlgorithm *m_optimizationalgorithm;
    WorkerThread *m_workerThread;
    QThread *m_thread;
    ..
private slots:
    void on_pushButton_run_clicked();
    void registrationDone();

我需要将timeConsumingMethod移动到一个单独的线程而不是主线程,以便在timeConsumingMethod运行时GUI不会冻结。 我创造了一个新课程" WorkerThread"使用Qt的官方文档,看起来像:

class WorkerThread : public QObject
{
    Q_OBJECT

public:
    WorkerThread(ApplicationData* data, QOptimizationAlgorithm * OptimizationAlgorithm);
    ~WorkerThread();

    public slots:
        void run(data* data);

signals:
    void finished();
    private slots:

private:
    OptimizationAlgorithm *m_OptimizationAlgorithm;
    ApplicationData *m_data;
}

我现在如何在run()中实施WorkerThread?我可以简单地写一下:

void WorkerThread::run(data *m_data)
{
    m_optimization.timeConsumingMethod(m_data);
    emit finished();
}

还是我必须在timeConsumingMethod中复制run()的整个定义?为什么/为什么不呢?

1 个答案:

答案 0 :(得分:2)

您不需要进行任何明确的线程管理,Qt已经为您完成了。使用QtConcurrent::run在线程池的工作线程中完成工作。

您还应该解耦管理工作的控制器和UI。如何耦合这些对象的知识应该与对象本身分开。这样可以更灵活地设计UI和控制器,并有助于避免因错误线程访问非线程安全方法而导致的几类错误。

完整示例:

// https://github.com/KubaO/stackoverflown/tree/master/questions/threadwork-simple-40865259
#include <QtWidgets>
#include <QtConcurrent>

struct ApplicationData {};

struct OptimizationAlgorithm {
   void timeConsumingMethod(QSharedPointer<ApplicationData>) {
      QThread::sleep(3);
   }
};

class Controller : public QObject {
   Q_OBJECT
   QSharedPointer<ApplicationData> m_data{new ApplicationData};
   OptimizationAlgorithm m_algorithm;
public:
   Q_SLOT void run() {
      QtConcurrent::run([this]{
         emit busy();
         m_algorithm.timeConsumingMethod(m_data);
         emit finished();
      });
   }
   Q_SIGNAL void busy();
   Q_SIGNAL void finished();
};

class Registration : public QWidget {
   Q_OBJECT
   QVBoxLayout m_layout{this};
   QLabel m_status{"Idle"};
   QPushButton m_run{"Run"};
public:
   Registration() {
      m_layout.addWidget(&m_status);
      m_layout.addWidget(&m_run);
      connect(&m_run, &QPushButton::clicked, this, &Registration::reqRun);
   }
   Q_SIGNAL void reqRun();
   Q_SLOT void onBusy() { m_status.setText("Running"); }
   Q_SLOT void onFinished() { m_status.setText("Idle"); }
};

void setup(Registration *reg, Controller *ctl) {
   using Q = QObject;
   Q::connect(reg, &Registration::reqRun, ctl, &Controller::run);
   Q::connect(ctl, &Controller::busy, reg, &Registration::onBusy);
   Q::connect(ctl, &Controller::finished, reg, &Registration::onFinished);
}

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   Controller ctl;
   Registration reg;
   setup(&reg, &ctl);
   reg.show();
   return app.exec();
}
#include "main.moc"