10

私は StackOverflow が初めてで、これを正しく行っているかどうか疑問に思っています。

マルチスレッドをテストするための簡単な Qt アプリケーションを作成しています (私もまったく新しいものです)。ウィジェットを含む MainWindow と、QThread をサブクラス化し、run() メソッドをオーバーライドするクラス MyThread を作成しました。

アプリケーションは、「Start Counter」と「Stop Counter」の 2 つのボタンと、テキスト フィールドを表示するだけです。「カウンターの開始」が押されると、ワーカー スレッドが作成されてバックグラウンドで実行され、while ループでカウンターが継続的にインクリメントされ、更新された値でメイン スレッド (GUI がある場所) に通知されます。「Stop Counter」が押されると、シグナルがメインスレッドに送信され、while ループが停止され、「Start Counter」が再度押されるまでカウンターが停止します。

これは完全にうまく機能します...しかし、それが最善の方法ですか? 私はこれが初めてで、「QThreadをサブクラス化しないでください」と言っている人や「QThreadをサブクラス化する」と言っている人をたくさん読んで、少し混乱しています。これがこの種の実装 (「開始」ボタンと「停止」ボタンを使用してバックグラウンド スレッドで計算集約型のループを実行する) の最良の方法ではない場合、何ですか? やり方が間違っている場合、どうすれば正しくできますか? 間違った方法で学びたくない。

ありがとうございました!コードは次のとおりです。

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

2 に答える 2

5

ほとんどの場合、QThread のサブクラス化は、Qt でスレッド化を行うには間違った方法です。スレッド、イベント ループなどに関する記事を読んで、Qt でスレッドをより適切に使用する方法を理解することをお勧めします。しかし、QThread を使用する唯一の正しい方法があると主張する人の言うことを聞かないでください。2 つの方法があり、一般にサブクラス化は必要ありませんが、役立つ場合もあります。本当にサブクラス化する必要があるまで、非サブクラス化の方法を使用する必要があります。あなたの特定のケースでは、サブクラス化は必要ありません。

于 2013-03-05T05:08:01.810 に答える
2

Things に置き換えsleep(1/1000);msleep(100);も問題ありません:)

于 2016-11-25T17:09:07.470 に答える