2

スタート ボタン、ストップ ボタン、およびテキスト フィールドを備えた単純な Qt4 アプリケーションがあります。[開始] ボタンが押されると、(while ループで) カウンターを継続的にインクリメントする新しいスレッドが生成され、シグナル/スロットを介してこれを反映するようにテキスト フィールドが更新されます。停止ボタンを押すと、再度開始ボタンを押すまでカウントが停止します。

それは動作します...一種の。カウンターは 1 秒に 1 回だけ更新されます。毎秒44100回など、もっと速くしたいです。ただし、sleep(1) 呼び出しを実行すると、while ループがブロックされ、GUI イベントが認識されず、アプリケーションがフリーズします。また、停止ボタンは 2 回目の試行でしか機能しませんか?

これは、QThread をサブクラス化していたときにかなりうまく機能していましたが、そうしないように言われたので、QObject をサブクラス化してからオブジェクトを QThread に移動して解決策を作成しようとしましたが、うまく機能しません。以前のように。

コードは次のとおりです。

Worker.h

class Worker : public QObject
{
  Q_OBJECT

  public:
    Worker();

  public slots:
    void process();
    void stopRunning();

  signals:
    void signalValueUpdated(QString);

  private:
    bool running;
};

ワーカー.cpp

#include "Worker.h"

void Worker::process()
{
    qDebug("Worker thread id %d",(int)QThread::currentThreadId());

    static int value=0;
    running = 1;
    while(running == 1)
    {
        QString string = QString("value: %1").arg(value++);
        sleep(1); //I want to take this out or make it way shorter but I can't without it crashing.

        emit signalValueUpdated(string);

        QCoreApplication::processEvents();       
    }
}

void Worker::stopRunning()
{
    qDebug("stopRunning() invoked");
    running = 0;
}

MainWindow.h

class MainWindow : public QWidget
{
  Q_OBJECT

  public:
    MainWindow(QWidget *parent = 0);

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

    //Thread where the worker lives
    QThread * workerThread;
    //Worker object itself
    Worker * worker;
};

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

    workerThread = new QThread;
    worker = new Worker();
    worker->moveToThread(workerThread);

    connect( startButton, SIGNAL(clicked()), workerThread, SLOT(start()), Qt::QueuedConnection ); //When the start button is clicked, start the worker thread
    connect( startButton, SIGNAL(clicked()), worker, SLOT(process()), Qt::QueuedConnection ); //When the start button is clicked, start the worker thread
    connect( workerThread, SIGNAL(started()), worker, SLOT(process()), Qt::QueuedConnection ); //When the worker thread starts, begin the Worker object's process function
    connect( stopButton, SIGNAL(clicked()), worker, SLOT(stopRunning()), Qt::QueuedConnection ); //When the stop button is clicked, invoke the Worker's stopRunning()
    connect( worker, SIGNAL(signalValueUpdated(const QString&)), lineEdit, SLOT(setText(const QString&)), Qt::QueuedConnection ); //When the Worker emits a signalValueChanged, update the lineEdit to reflect this

}

Worker.cpp に sleep(1) と processEvents() がないと、全体がクラッシュしますが、遅くなりすぎて、1000 以上ではなく 1 秒に 1 回しか更新されません。while(running) ループをブロックしないようにするにはどうすればよいですか?

前もって感謝します!Qt でマルチスレッドを実行するための最良の方法に頭を悩ませようとしています。

4

1 に答える 1

2
  1. 不要な場合は、ワーカーで削除QCoreApplication::processEvents()します (なぜ必要なのですか? GUI イベントは、メイン スレッドによって既に処理されているはずです...)。それがあなたの問題の原因かもしれません。

  2. スレッド シグナルを正しい方法で接続します。

    connect(workerThread, SIGNAL(started()), worker, SLOT(process()));
    connect(startButton, SIGNAL(clicked()), thread, SLOT(start()));
    

    startButton.clicked()(コメントに書いてあることを-> -の接続を外す-worker.process()ダメでやらない)

    なぜ削除する必要があるのですか?

    ボタンをワーカー内のプロセスに直接接続するのは正しくないためです。ボタンを Thread の先頭に接続し、次に Thread (開始済み) を worker に接続する必要がありますprocess()。直接接続を避けることで、直面している GUI フリーズの問題を回避できます。

また、ボタンをクリックするたびに、新しいスレッドを作成して「起動」する必要があります。ボタンをウィンドウの に配線し、SLOTそこからスレッドを作成することで実行できます (MainWindowコンストラクターでの作成は機能しません)。


私が持っている(作業中の)プログラムから取られました:

  // You need another slot in MainWindow, let it be "startProcessing()"
  // in MainWindow::MainWindow, connect the start button to startProcessing()
  connect(btnStart, signal(clicked(), this, SLOT(startProcessing())


  // inside the startProcessing slot
  void MainWindow::startProcessing() {
     ...
     Worker* worker = new Worker;
     QThread* thread = new QThread;

     // start the work
     worker->moveToThread(thread);
     connect(thread, SIGNAL(started()), worker, SLOT(process()));

     // Take care of cleaning up when finished too
     connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
     connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
     connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

     thread->start(); 
  }

お気づきかもしれませんが、クリーンアップするためのコードも追加しました ( deleteLater())。

停止ボタンもいくつかの問題を引き起こしますが、続行する方法については良いアイデアが得られるはずです。

于 2013-03-05T08:22:21.317 に答える