2016-11-29 1 views
1

J'ai un code C++ incluant une interface graphique, dans lequel j'ai besoin d'exécuter une boucle de temps pour l'optimisation.Utilisation de QThread Basic en C++

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

ce besoin d'être appelé dans une classe GUI comme suit:

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(); 

J'ai besoin de déplacer le timeConsumingMethod dans un fil séparé de fil conducteur, de sorte que l'interface graphique ne freez en timeConsumingMethod est fonctionnement. J'ai fait une nouvelle classe « WorkerThread » en utilisant la documentation officielle de Qt, qui ressemble à:

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; 
} 

Comment shoud je mettre en œuvre maintenant mon run() en WorkerThread? Puis-je écrire simplement:

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

ou dois-je copier la définition de toute timeConsumingMethod dans run()? Pourquoi pourquoi pas?

+2

Vous n'avez pas besoin de réimplémenter méthode 'run' si vous utilisez un modèle « travailleur ». Essayez de lire la documentation Qt, il existe des exemples parfaits. –

+1

Vous n'avez pas besoin de copier la définition complète de timeConsumingMethod, tout code appelé dans run() s'exécutera dans le thread de WorkerThread, pour prouver que la fonction QThread :: currentThreadId() est utilisée pour obtenir l'ID de thread. – nikitoz

Répondre

2

Vous n'avez pas besoin d'effectuer une gestion de thread explicite, Qt le fait déjà pour vous. Utilisez QtConcurrent::run pour effectuer le travail dans un thread de travail à partir du pool de threads.

Vous devez également découpler le contrôleur qui gère le travail et l'interface utilisateur. La connaissance de la façon de coupler ces objets doit être séparée des objets eux-mêmes. Cela permet une plus grande flexibilité dans la conception de l'interface utilisateur et du contrôleur, et permet d'éviter plusieurs classes d'erreurs résultant de l'accès à des méthodes non thread-safe à partir de threads incorrects.

Exemple complet:

// 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"