首页 > 代码库 > Qt - QThread(翻译帮助文档)
Qt - QThread(翻译帮助文档)
QThread Class 详细描述
QThread 类提供一个平台无关的方法来管理线程。
一个QThread对象管理一个程序中的控制线程。QThread在run()中开始执行任务。默认地,run()通过调用exec()开始事件循环,并且在线程中运行Qt事件循环。
你可通过使用QObject::moveToThread()将worker对象移到线程中来使用worker对象。
class Worker : public QObject { Q_OBJECT public slots: void doWork(const QString ¶meter) { QString result; /* ... here is the expensive or blocking operation ... */ 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槽中的代码会在一个单独的线程中执行。然而,你可以自由地将Woker的槽和任何信号相连,不管信号来自哪个对象,在哪个线程中。一个叫做queued connections的机制保证跨不同线程的信号(signals)和槽(slots)的连接(connect)是安全的。
另外一种将代码运行在独立线程的方法是通过QThread的子类重新实现run()。例如:
1 class WorkerThread : public QThread 2 { 3 Q_OBJECT 4 void run() Q_DECL_OVERRIDE { 5 QString result; 6 /* ... here is the expensive or blocking operation ... */ 7 emit resultReady(result); 8 } 9 signals: 10 void resultReady(const QString &s); 11 }; 12 13 void MyObject::startWorkInAThread() 14 { 15 WorkerThread *workerThread = new WorkerThread(this); 16 connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults); 17 connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater); 18 workerThread->start(); 19 }
在上述示例中,线程在run()返回后会退出。线程中没有任何事件循环执行除非你调用exec()。
需要记住的是QThread实例依存于实例它的旧线程中,不是在调用run()的新线程中。这意味着所有QThread的队列化的槽会在旧线程中执行。因此,开发者想要在新线程中调用槽函数需要使用工作者对象方法(woker-object approach);新的槽函数不应该直接在QThread的子类中实现。
当定义QThread的子类时,需注意子类的构造函数(constructor)在旧线程中执行,run()在新线程中执行。如果一个成员变量被两个函数访问,则该成员变量是在不同的线程中访问,需要检查访问是否安全(线程同步)。
线程管理
QThread在线程started()和finished()时会通过信号(signa)通知你,或者你可以通过isFinished()和isRunning()查询线程的状态。
你可以通过调用exit()或者quit()停止线程。极端情况下,你可能想通过terminate()强制结束一个线程,但是这样做是危险的,不鼓励如此。
从Qt4.8开始,当线程刚刚结束时,可以将线程中的对象释放(deallocate),方法是连接finished()信号和QObject::deleteLater()。
使用wait()阻塞调用线程,直到其他线程执行完成(或者指定的时间已过)。
QThread也提供静态的、平台无关的睡眠函数(sleep):sleep(),msleep(),usleep(),分别的精度是秒,毫秒,微秒。
Note:wait()和sleep()函数一般不需要,因为Qt是一个事件驱动框架。考虑监听finished()信号替换wait()函数,用QTimer替换sleep()函数。
静态函数currentThreadId()和currentThread()返回当前执行线程的标识。前者返回平台为线程指定的ID,后者返回一个QThread指针。
在启动线程之前调用setObjectName(),可选择线程名字(类似于linux命令 ps -L)。如果不调用setObjectName(),给定的线程名字是线程对象运行时类名字。注意在Windows系统release builds时,该函数暂不可用。
Qt - QThread(翻译帮助文档)