5

プッシュボタンを使用してスレッドを頻繁に開始および停止する必要があります。Qtを使用しています。最近、Qtでスレッドを実装する正しい方法として、ワーカーのQObjectを作成し、それをQThreadのオブジェクトに移動することを学びました。以下は私の実装です...

Worker.h

class worker : public QObject
{
    Q_OBJECT
public:
    explicit worker(QObject *parent = 0);
    void StopWork();
    void StartWork();
    bool IsWorkRunning();

signal:
    void SignalToObj_mainThreadGUI();

public slots:
    void do_Work();

private:
    void Sleep();

    volatile bool running,stopped;
    QMutex mutex;
    QWaitCondition waitcondition;
};

Worker.cpp

 worker::worker(QObject *parent) :
    QObject(parent),stopped(false),running(false)
{
}

void worker::do_Work()
{
    running = true;
    while(!stopped)
    {
        emit SignalToObj_mainThreadGUI();
        Sleep();
    }
}

void worker::Sleep()
{
    mutex.lock();
    waitcondition.wait(&mutex,10);
    mutex.unlock();
}

void worker::StopWork()
{
    mutex.lock();
    stopped = true;
    running = false;
    mutex.unlock();
}

void worker::StartWork()
{
    mutex.lock();
    stopped = false;
    running = true;
    mutex.unlock();
}

bool worker::IsWorkRunning()
{
    return running;
}

MainWindow.h

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

public slots:

private slots:
    void on_pushButton_push_to_start_clicked();

    void on_pushButton_push_to_stop_clicked();

private:

    Ui::MainWindow *ui;
    worker *myWorker;
    QThread *WorkerThread;
};

MainWindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    myWorker = new worker;
    WorkerThread = new QThread;
    myWorker.moveToThread(WorkerThread);

    QObject::connect(WorkerThread,SIGNAL(started()),myWorker,SLOT(do_Work()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_push_to_start_clicked()
{
    if(!myWorker.IsWorkRunning())
       {
         myWorker->StartWork();
         WorkerThread->start();
       }
}

void MainWindow::on_pushButton_push_to_stop_clicked()
{
  if(myWorker.IsWorkRunning())
     {
       myWorker->StopWork();
       WorkerThread->quit();
     }
}

最初はアプリケーションは正常に動作しますが、プッシュボタンを操作してスレッドの動作をオンまたはオフにすると、次のエラーが発生します...

QObject :: killTimers():タイマーを別のスレッドから停止することはできません

私はこのエラーにかなり戸惑っています...クラスのメンバー関数ではなく、信号とスロットとして開始/停止関数を実装する必要がありますか?

4

1 に答える 1

8

開始および停止しないでくださいWorkerThread。実行したままにしておきます。また、メソッドStartWork()StopWork()メソッドをパブリックスロットセクションに移動します。ミューテックスはまったく必要ありません。

Worker.h

class worker : public QObject
{
  Q_OBJECT
public:
  explicit worker(QObject *parent = 0);

signal:
  void SignalToObj_mainThreadGUI();
  void running();
  void stopped();

public slots:
  void StopWork();
  void StartWork();

private slots:
  void do_Work();

private:
  volatile bool running,stopped;
};

Worker.cpp

worker::worker(QObject *parent) :
  QObject(parent), stopped(false), running(false)
{}

void worker::do_Work()
{
  emit SignalToObj_mainThreadGUI();

  if ( !running || stopped ) return;

  // do important work here

  // allow the thread's event loop to process other events before doing more "work"
  // for instance, your start/stop signals from the MainWindow
  QMetaObject::invokeMethod( this, "do_Work", Qt::QueuedConnection );
}

void worker::StopWork()
{
  stopped = true;
  running = false;
  emit stopped();
}

void worker::StartWork()
{
  stopped = false;
  running = true;
  emit running();
  do_Work();
}

MainWindow.h

namespace Ui {
  class MainWindow;
}

class MainWindow : public QMainWindow
{
  Q_OBJECT
public:
  explicit MainWindow(QWidget *parent = 0);
  ~MainWindow();

signals:
  void startWork();
  void stopWork();

private slots:
  void on_pushButton_push_to_start_clicked();
  void on_pushButton_push_to_stop_clicked();

private:
  Ui::MainWindow *ui;
  worker *myWorker;
  QThread *WorkerThread;

};

MainWindow.cpp

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{
  ui->setupUi(this);

  myWorker = new worker;
  WorkerThread = new QThread;
  myWorker.moveToThread(WorkerThread);

  connect( this, SIGNAL(startWork()), myWorker, SLOT(StartWork()) );
  connect( this, SIGNAL(stopWork()), myWorker, SLOT(StopWork()) );
}

void MainWindow::on_pushButton_push_to_start_clicked()
{
  emit startWork();
}

void MainWindow::on_pushButton_push_to_stop_clicked()
{
  emit stopWork();
}
于 2013-01-25T16:56:19.407 に答える