一、QThread类概述
QThread类为用户管理多线程提供了一种平台无关的途径。
#include <QThread>
继承自QObject类
二、QThread类详述
QThread对象在程序内部进行控制线程的管理,QThread起始于run()函数额执行。默认情况下,run()通过调用exec()启动事件循环(event loop),并在线程内部执行Qt 的事件循环。
以下示例通过QObject::moveToThread()调用把worker对象添加到线程中运行:
class Worker : public QObject { Q_OBJECT QThread workerThread; public slots: void doWork(const QString str) { // ... 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, SIGNAL(finished()), worker, SLOT(deleteLater())); connect(this, SIGNAL(operate(QString)), worker, SLOT(doWork(QString))); connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString))); workerThread.start(); } ~Controller() { workerThread.quit(); workerThread.wait(); } public slots: void handleResults(const QString &); signals: void operate(const QString &); };
Worker槽中的代码以后就在一个独立的线程中运行。你可以按自己意愿,把Worker槽(slots )连接到任何对象的信号(signal)上。得益于队列连接(queued connections) 机制(一个事件被派发到接收者所在线程的事件循环,当事件被传递,相应的槽随之被激活),在不同对象间进行信号和槽的连接是安全的。
另外一种实现多线程的方式是继承QThread类,并重新实现run()函数,例如:
class Thread : public QThread { Q_OBJECT public: Thread(); void setMessage(const QString &message); void stop(); protected: void run(); private: QString messageStr; volatile bool stopped; QUdpSocket *udpSpcket; }; class ThreadDialog : public QDialog { Q_OBJECT public: ThreadDialog(QWidget *parent = 0); protected: void closeEvent(QCloseEvent *event); private slots: void startOrStopThreadA(); void startOrStopThreadB(); private: Thread threadA; Thread threadB; QPushButton *threadAButton; QPushButton *threadBButton; };
注意:
1、当run()函数返回的以后,线程会退出(exit)。如果没有调用exec()函数,该线程中不存在任何运行状态的事件循环(event loop)。
2、重要的是,QThread对象通常存在于(lives in)创建他的线程中,而不是它管理的线程中。这意味着,QThread的槽是在它存在的线程(home thread)的上下文中被执行,而不是它管理的线程的上下文中。基于这一点,在QThread子类中实现新的槽是容易出错所以是不被提倡的。
3、如果使用其他方法(technique)在不同对象间进行交互,而不是队列性的信号-槽(signal/slot)机制,那么在多线程程序中就要预先警惕可能出现的问题。
4、GUI对象的线程必须存在于主线程(main thread)中。
三、管理QThread
Managing threads
当线程开始运行(started())、执行完毕(finished())、终止(terminated())的时候,QThread通过信号()进行通知;反过来,也可以调用isFinished()和isRunning()查询线程的状态。
要想停止(stop)线程,可以通过调用exit()或quit()实现,在极端情况下,可以调用terminate()强制终止一个执行状态的线程——但是这样比较危险,并不提倡,使用setTerminationEnabled()函数可以使能/禁止terminate()函数。
Qt 4.8以后,通过把finished()信号连接到QObject::deleteLater()槽上,可以在线程结束后删除(deallocate)对象。
使用wait()可以阻塞调用线程,直到其他线程执行结束(也可以指定一个超时时间)。
静态(static)函数currentThreadId()和currentThread()返回当前执行线程的的标识符(identifiers),
在线程启动前调用setObjectName()可以给线程指定一个名字,作为和其他线程的区别标识。如果没有调用setObjectName(),将以线程对象运行时类型的类名作为线程的名字。比如,下面例子中,线程的名字是RenderThread:
class RenderThread : public QThread { Q_OBJECT public: RenderThread(QObject *parent = 0); ~RenderThread(); void render(double centerX, double centerY, double scaleFactor, QSize resultSize); signals: void renderedImage(const QImage &image, double scaleFactor); protected: void run(); private: uint rgbFromWaveLength(double wave); QMutex mutex; QWaitCondition condition; };注意:这种规则目前不适用于在Windows闪编译的release。
QThread类提供了static类型,平台无关的sleep函数:sleep(),msleep(),usleep(),经度分别是秒、毫秒、微秒。
注意:一般来讲,wait()和sleep()应该是不必要的(unnecessary),因为Qt是基于事件驱动(event-driven)的架构。使用wait()的时候,考虑下finished(),sleep()时,考虑下QTimer。
四、QThread优先级
enum Qthread::Priority
常量 |
值 |
描述 |
QThread::IdlePriority |
0 |
没有其他线程运行时才进行调度 |
QThread::LowestPriority |
1 |
不比LowPriority调度频繁 |
QThread::LowPriority |
2 |
不比NormalPriority调度频繁 |
QThread::NormalPriority |
3 |
操作系统的默认优先级 |
QThread::HighPriority |
4 |
比NormalPriority调度频繁 |
QThread::HighestPriority |
5 |
比HighPriority调度频繁 |
QThread::TimeCriticalPriority |
6 |
尽可能频繁的进行调度 |
QThread::InheritPriority |
7 |
使用和创建自己的线程同样的优先级,这是默认属性 |
原文:http://blog.csdn.net/u013686019/article/details/38851353