2012-12-27 113 views
4

我需要使用按鈕來非常頻繁地啓動和停止線程..我正在使用Qt。最近我學會了創建工作者的QObject,並將其移至QThread的對象,作爲在Qt中實現線程的正確方式。以下是我的實現......如何實現線程的頻繁啓動/停止(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():定時器不能從另一個線程

停止我挺納悶的,在這個錯誤...我需要實現起動/停止功能作爲類的信號和槽,而不是成員函數?

+3

儘量不要調用start()和退出()在你的線程。將工作對象移動到線程後,您應該直接控制工作人員。 start()和quit()僅用於啓動和關閉線程。 –

回答

3

不要啓動和停止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(); 
} 
+0

關於invokeMethod:當我使用你的代碼時,它不起作用,根據http://qt-project.org/doc/qt-4.8/qmetaobject.html#invokeMethod,你應該使用字符串「do_Work」而不是SLOT(do_Work) ())。這對我有效。 – sluki

+0

@sluki:你說'invokeMethod'參數是正確的。我更新了我的答案以使用正確的格式。 –

+0

偉大的答案謝謝!稍微跟進一下,說你有do_Work函數,while(循環)我該如何中斷那個動作?我注意到QueuedConnection在處理它時不會停止循環,所以我想我必須以某種方式檢查它自己? – Dariusz