2013-03-05 12 views
8

Jestem nowy w StackOverflow i zastanawiam się, czy robię to dobrze:Proste wielowątkowość z Qt: czy robię to dobrze?

Piszę prostą aplikację Qt, aby przetestować wielowątkowość (coś, do czego jestem również całkowicie nowy). Zrobiłem MainWindow, który zawiera widżety i klasę MyThread, która podklasuje QThread i nadpisuje metodę run().

Aplikacja po prostu wyświetla dwa przyciski "Start Counter" i "Stop Counter" oraz pole tekstowe. Po naciśnięciu "licznika startu" tworzony jest wątek roboczy, który działa w tle, stale zwiększając licznik w pętli while i sygnalizując główny wątek (gdzie GUI jest) z zaktualizowaną wartością. Po naciśnięciu przycisku "Stop Counter" sygnał jest wysyłany do głównego wątku, który zatrzymuje pętlę while, a licznik jest zatrzymywany do momentu ponownego naciśnięcia przycisku "Start Counter".

Działa to idealnie dobrze ... ale czy to najlepszy sposób? Jestem w tym nowy i czytam wielu ludzi mówiących "nie podklas QThread" i innych ludzi mówiących "podklasę QThread", i to jest nieco mylące. Jeśli nie jest to najlepszy sposób na implementację tego rodzaju rzeczy (uruchom wymagającą obliczeniowo pętlę w wątku tła za pomocą przycisków "start" i "stop"), co to jest? Jeśli robię to źle, jak mam to zrobić dobrze? Nie chcę się uczyć w niewłaściwy sposób.

Dziękujemy! A oto kod:

MyThread.h

#ifndef MYTHREAD_H 
#define MYTHREAD_H 

#include <QThread> 
#include <QMutex> 

class MyThread : public QThread 
{ 
    Q_OBJECT 

public slots: 
    void stopRunning(); 

protected: 
    virtual void run(); 

signals: 
    void signalValueUpdated(QString); 

private: 
    bool isRunning; 

}; 

MyThread.cpp

#include "MyThread.h" 
#include <QString> 

void MyThread::run() 
{ 
    qDebug("Thread id inside run %d",(int)QThread::currentThreadId()); 

    static int value=0; //If this is not static, then it is reset to 0 every time this function is called. 
    isRunning = 1; 
    while(isRunning == 1) 
    { 
     QString string = QString("value: %1").arg(value++); 
     sleep(1/1000); //If this isn't here, the counter increments way too fast and dies, or something; the app freezes, anyway. 

     emit signalValueUpdated(string);  
    }    
} 

void MyThread::stopRunning() 
{ 
    isRunning = 0; 
} 

MainWindow.h

#ifndef MAINWINDOW_H 
#define MAINWINDOW_H 

#include <QApplication> 
#include <QPushButton> 
#include <QHBoxLayout> 
#include <QLineEdit> 
#include "MyThread.h" 

class MainWindow : public QWidget 
{ 
    Q_OBJECT 

    public: 
    MainWindow(QWidget *parent = 0); 

    private: 
    //Widgets 
    QHBoxLayout * boxLayout; 
    QPushButton * startButton; 
    QPushButton * stopButton; 
    QLineEdit * lineEdit; 

    MyThread thread; 
}; 

#endif 

MainWindow.cpp

#include "MainWindow.h" 

MainWindow::MainWindow(QWidget *parent) : QWidget(parent) 
{ 
    boxLayout = new QHBoxLayout(this); 
    startButton = new QPushButton("Start Counter", this); 
    stopButton = new QPushButton("Stop Counter", this); 
    lineEdit = new QLineEdit(this); 

    boxLayout->addWidget(startButton); 
    boxLayout->addWidget(stopButton); 
    boxLayout->addWidget(lineEdit); 

    qDebug("Thread id %d",(int)QThread::currentThreadId()); 

    //When the start button is pressed, invoke the start() method in the counter thread 
    QObject::connect(startButton,SIGNAL(clicked()),&thread,SLOT(start()), Qt::QueuedConnection); 

    //When the stop button is pressed, invoke the stop() method in the counter thread 
    QObject::connect(stopButton,SIGNAL(clicked()),&thread,SLOT(stopRunning()), Qt::QueuedConnection); 

    //When the counter thread emits a signal saying its value has been updated, reflect that change in the lineEdit field. 
    QObject::connect(&thread,SIGNAL(signalValueUpdated(const QString&)),lineEdit,SLOT(setText(const QString&)), Qt::QueuedConnection); 
} 
+1

Uważać 'sleep (1/1000)' 'oznacza sen (0)'. – deepmax

+0

@M M. Dobry połów – Throwback1986

+0

Dobry połów, dzięki! Zmieniono go na sen (0,001). – evdc

Odpowiedz

4

Większość czasu QThread sub-classing jest niewłaściwy sposób zrobić gwint w Qt. Proponuję przeczytać article about threads, event loops and other, który może dać ci pomysł lepszego wykorzystania wątków w Qt. Ale nie słuchaj nikogo, kto twierdzi, że istnieje jedyny właściwy sposób używania QThread. Istnieją dwa sposoby i podczas gdy podklasowanie nie jest ogólnie potrzebne, czasami może się przydać. Musisz tylko używać metod nie-podklasowych, dopóki naprawdę nie potrzebujesz podklasy. W twoim przypadku nie potrzebujesz podklasy.

+1

A więc, czym właściwie jest _disadvantage_ of using podklasy? (To dlaczego mam _nie_ używać?) Wydaje mi się, że jest o wiele łatwiejsze niż tworzenie oddzielnego QThread i oddzielnym wątku roboczego, a następnie robi moveToThread(). Przynajmniej, gdy używa się podklasy, znacznie łatwiej jest zrozumieć, co się dzieje. –

+0

@GijsvanOort, artykuł wspomniałem powyżej odpowiedzi na swoje pytanie. – ixSci

1

Wymień sleep(1/1000); z msleep(100); wszystko będzie dobrze :)