2012-12-27 67 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