2016-11-29 6 views
1

Ich habe einen C++ Code einschließlich GUI, in dem ich eine zeitaufwändige Schleife für die Optimierung ausführen muss.QThread Grundlegende Verwendung in C++

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

dieses Bedürfnis in einer GUI-Klasse aufgerufen werden wie folgt vor:

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

ich die timeConsumingMethod in einen separaten Thread als Haupt-Thread verschieben müssen, so dass die GUI nicht freez tut, während timeConsumingMethod ist Laufen. Ich habe eine neue Klasse „WorkerThread“ mit der offiziellen Dokumentation von Qt, gemacht, die wie folgt aussieht:

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

Wie shoud ich jetzt meine run() in WorkerThread implementieren? Kann ich einfach schreiben:

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

oder muss ich die ganze Definition von timeConsumingMethod in run() kopieren? Warum Warum nicht?

+2

Sie brauchen nicht 'run' Methode neu zu implementieren, wenn Sie ein„Arbeiter“Muster verwenden. Versuchen Sie, Qt-Dokumentation zu lesen, es gibt perfekte Beispiele. –

+1

Sie müssen nicht die gesamte Definition von timeConsumingMethod kopieren, jeder Code, der in run() aufgerufen wird, wird im WorkerThread-Thread ausgeführt, um zu überprüfen, ob die QThread :: currentThreadId() -Funktion zum Abrufen der Thread-ID verwendet wird. – nikitoz

Antwort

2

Sie müssen keine explizite Thread-Verwaltung vornehmen, Qt tut dies bereits für Sie. Verwenden Sie QtConcurrent::run, um die Arbeit in einem Worker-Thread aus dem Thread-Pool auszuführen.

Sie sollten auch den Controller, der die Arbeit verwaltet, und die Benutzeroberfläche entkoppeln. Das Wissen, wie man diese Objekte koppelt, sollte von den Objekten selbst getrennt sein. Dies ermöglicht mehr Flexibilität beim Entwurf der Benutzeroberfläche und des Controllers und hilft dabei, mehrere Fehlerklassen zu vermeiden, die beim Zugriff auf nicht threadsichere Methoden auf falsche Threads zurückzuführen sind.

Komplettes Beispiel:

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