Qt线程的应用

来源:互联网 发布:安卓串口助手源码 编辑:程序博客网 时间:2024/04/29 04:40

最近深入研究了一下Qt的多线程编程,简单总结一下Qt中的线程应用。

一、QThread类

QThread类提供了一个平台无关的方式来管理线程。一个QThread对象在程序控制中管理一个线程,线程在run()中执行。默认情况下,run()通过调用exec()启动事件循环,并在线程里运行一个Qt事件循环。

二、Qt线程的两种运行方式

1、QObject::moveToThread()将对象移至线程的方式

class Worker : public QObject{    Q_OBJECT    public slots:    void doWork(const QString &parameter) {        // ...        emit resultReady(result);    }signals:    void resultReady(const QString &result);};class Controller : public QObject{    Q_OBJECT    QThread workerThread;public:    Controller() {        Worker *worker = new Worker;        worker->moveToThread(&workerThread);        connect(workerThread, &QThread::finished, worker, &QObject::deleteLater);        connect(this, &Controller::operate, worker, &Worker::doWork);        connect(worker, &Worker::resultReady, this, &Controller::handleResults);        workerThread.start();    }    ~Controller() {        workerThread.quit();        workerThread.wait();    }public slots:    void handleResults(const QString &);signals:    void operate(const QString &);};

Worker槽中的代码将在一个单独的线程中执行,然而,可以将(来自任何对象、在任何线程中)任何信号与该槽自由地连接,在不同的线程里连接信号和槽也是安全的,这要归功于一个叫排队的连接机制(queued connections)。

2、子类化QThread并重新实现run函数的方式

class WorkerThread : public QThread{    Q_OBJECT    //防止写了错误的虚函数名称,可以使用 Q_DECL_OVERRIDE 宏来声明这是一个对虚函数进行定义的方法,来避免上述错误    void run() Q_DECL_OVERRIDE {        QString result;        emit resultReady(result);    }signals:    void resultReady(const QString &s);};void MyObject::startWorkInAThread(){    WorkerThread *workerThread = new WorkerThread(this);    connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);    connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);    workerThread->start();}

上面的例子中,在run()返回后线程就会退出,在线程中将不会有任何的事件循环运行除非调用exec()。
注意一个线程实例位于实例化它的旧线程中,而非调用run()的新线程中,这意味着所有线程的排队槽将在旧线程中执行。因此,开发人员希望在新线程调用槽必须使用worker-object方法,新槽不应直接在子类化QThread中来实现。当子类化QThread时,请记住,构造函数在旧线程中执行,然而run()在新线程中执行。如果一个成员变量的访问来自两个函数,然后从两个不同的线程访问变量,需要检查这样做是否安全。

三、Qt线程的管理

1、QThread会通知你触发了一个信号当线程started()和finished()时,或者使用isFinished()和isRunning()来查询线程的状态。

2、可以通过调用exit()或quit()来停止线程。在极端情况下,你可能要强行terminate()一个执行线程。但是,这样做是危险的。

3、从Qt4.8起,可以释放运行刚刚结束的线程对象,通过连接finished()信号到QObject::deleteLater()。

4、使用wait()来阻塞调用的线程,直到其他线程执行完毕(或者直到指定的时间过去)。
QThread中还提供了静态的、平台独立的休眠功能:sleep()、msleep()、usleep()允许秒,毫秒和微秒来区分,这些函数在Qt5.0中被设为public。
注意:一般情况下,wait()和sleep()函数应该不需要,因为Qt是一个事件驱动型框架。而不是wait(),关心监听信号finished()。取代sleep(),可以考虑使用QTimer。

5、静态函数currentThreadId()和currentThread()返回标识当前正在执行的线程。前者返回该线程的平台特定的ID,后者返回一个线程指针。

6、要设置线程的名称,可以在启动线程之前调用setObjectName()。如果不调用setObjectName(),线程的名称将是线程对象的运行时类型(上例中“WorkerThread”,因为这是QThread子类的类名)。请注意,基于Windows的构建版本目前不可用。

1 0