Qt之QThread用法
2017-02-07 22:53
1536 查看
QThread类提供了与系统无关的线程。
QThread代表在程序中一个单独的线程控制。线程在run()中开始执行,默认情况下,run()通过调用exec()启动事件循环并在线程里运行一个Qt的事件循环。
当线程started()和finished()时,QThread会通过一个信号通知你,可以使用isFinished()和isRunning()来查询线程的状态。
你可以通过调用exit()或quit()来停止线程。在极端情况下,可能要强行terminate()一个执行线程。但是,这样做很危险,下面会详细说明。
从Qt4.8起,可以释放运行刚刚结束的线程对象,通过连接finished()信号到QObject::deleteLater()槽。
使用wait()来阻塞调用的线程,直到其它线程执行完毕(或者直到指定的时间过去)。
QThread还提供了静态的、平台独立的休眠函数:sleep()、msleep()、usleep(),允许秒,毫秒和微秒来区分,这些函数在Qt5.0中被设为public。
注意:一般情况下,wait()和sleep()函数应该不需要,因为Qt是一个事件驱动型框架。考虑监听finished()信号来取代wait(),使用QTimer来取代sleep()。
静态函数currentThreadId()和currentThread()返回标识当前正在执行的线程。前者返回该线程平台特定的ID,后者返回一个线程指针。
要设置线程的名称,可以在启动线程之前调用setObjectName()。如果不调用setObjectName(),线程的名称将是线程对象的运行时类型(QThread子类的类名)。
可以将常用的接口按照功能进行以下分类
线程启动
void start(Priority priority = InheritPriority)[slot]
调用后会执行run()函数,但在run()函数执行前会发射信号started(),操作系统将根据优先级参数调度线程。如果线程已经在运行,那么这个函数什么也不做。优先级参数的效果取决于操作系统的调度策略
线程执行
int exec() [protected]
进入事件循环并等待直到调用exit(),返回值是通过调用exit()来获得,如果调用成功则范围0。
void run() [virtual protected]
线程的起点,在调用start()之后,新创建的线程就会调用这个函数,默认实现调用exec(),大多数需要重新实现这个函数,便于管理自己的线程。该方法返回时,该线程的执行将结束。
线程退出
void quit() [slot]
告诉线程事件循环退出,返回0表示成功,相当于调用了QThread::exit(0)。
void exit(int returnCode = 0)
告诉线程事件循环退出。调用这个函数后,线程离开事件循环后返回,QEventLoop::exec()返回returnCode,按照惯例,0表示成功;任何非0值表示失败。
void requestInterruption()
请求线程的中断。该请求是咨询意见并且取决于线程上运行的代码,来决定是否及如何执行这样的请求。此函数不停止线程上运行的任何事件循环,并且在任何情况下都不会终止它。
线程等待
void msleep(unsigned long msecs) [static]
强制当前线程睡眠msecs毫秒
void sleep(unsigned long secs) [static]
强制当前线程睡眠secs秒
void usleep(unsigned long usecs) [static]
强制当前线程睡眠usecs微秒
bool wait(unsigned long time = ULONG_MAX)
线程将会被阻塞,等待time毫秒。和sleep不同的是,如果线程退出,wait会返回。
线程状态
bool isFinished() const
线程是否结束
bool isRunning() const
线程是否正在运行
线程优先级
void setPriority(Priority priority)
设置正在运行线程的优先级。如果线程没有运行,此函数不执行任何操作并立即返回。使用的start()来启动一个线程具有特定的优先级。优先级参数可以是QThread::Priority枚举除InheritPriortyd的任何值。
枚举QThread::Priority:
子类化QThread
上面的示例,在run()函数返回后线程就会退出,在线程中将不会有任何的事件循环运行,除非调用exec()。
重要的是要记住,一个线程实例位于实例化它的旧线程中,而非调用run()的新线程中,这意味着所有线程的queued slots将在旧线程中执行。
采取合理的措施来优雅地结束线程,一般思路:
发起线程退出操作,调用quit()或exit()。
等待线程完全停止,删除创建在堆上的对象。
适当的使用wait()(用于等待线程的退出)和合理的算法。
当主线程调用stop()更新m_bStopped的时候,run()函数也极有可能正在访问它(这时,他们处于不同的线程),所以存在资源竞争,因此需要加锁,保证共享数据的安全性。
主线程会调用deleteLater,然后自动调用析构函数!
QThread代表在程序中一个单独的线程控制。线程在run()中开始执行,默认情况下,run()通过调用exec()启动事件循环并在线程里运行一个Qt的事件循环。
当线程started()和finished()时,QThread会通过一个信号通知你,可以使用isFinished()和isRunning()来查询线程的状态。
你可以通过调用exit()或quit()来停止线程。在极端情况下,可能要强行terminate()一个执行线程。但是,这样做很危险,下面会详细说明。
从Qt4.8起,可以释放运行刚刚结束的线程对象,通过连接finished()信号到QObject::deleteLater()槽。
使用wait()来阻塞调用的线程,直到其它线程执行完毕(或者直到指定的时间过去)。
QThread还提供了静态的、平台独立的休眠函数:sleep()、msleep()、usleep(),允许秒,毫秒和微秒来区分,这些函数在Qt5.0中被设为public。
注意:一般情况下,wait()和sleep()函数应该不需要,因为Qt是一个事件驱动型框架。考虑监听finished()信号来取代wait(),使用QTimer来取代sleep()。
静态函数currentThreadId()和currentThread()返回标识当前正在执行的线程。前者返回该线程平台特定的ID,后者返回一个线程指针。
要设置线程的名称,可以在启动线程之前调用setObjectName()。如果不调用setObjectName(),线程的名称将是线程对象的运行时类型(QThread子类的类名)。
可以将常用的接口按照功能进行以下分类
线程启动
void start(Priority priority = InheritPriority)[slot]
调用后会执行run()函数,但在run()函数执行前会发射信号started(),操作系统将根据优先级参数调度线程。如果线程已经在运行,那么这个函数什么也不做。优先级参数的效果取决于操作系统的调度策略
线程执行
int exec() [protected]
进入事件循环并等待直到调用exit(),返回值是通过调用exit()来获得,如果调用成功则范围0。
void run() [virtual protected]
线程的起点,在调用start()之后,新创建的线程就会调用这个函数,默认实现调用exec(),大多数需要重新实现这个函数,便于管理自己的线程。该方法返回时,该线程的执行将结束。
线程退出
void quit() [slot]
告诉线程事件循环退出,返回0表示成功,相当于调用了QThread::exit(0)。
void exit(int returnCode = 0)
告诉线程事件循环退出。调用这个函数后,线程离开事件循环后返回,QEventLoop::exec()返回returnCode,按照惯例,0表示成功;任何非0值表示失败。
void requestInterruption()
请求线程的中断。该请求是咨询意见并且取决于线程上运行的代码,来决定是否及如何执行这样的请求。此函数不停止线程上运行的任何事件循环,并且在任何情况下都不会终止它。
线程等待
void msleep(unsigned long msecs) [static]
强制当前线程睡眠msecs毫秒
void sleep(unsigned long secs) [static]
强制当前线程睡眠secs秒
void usleep(unsigned long usecs) [static]
强制当前线程睡眠usecs微秒
bool wait(unsigned long time = ULONG_MAX)
线程将会被阻塞,等待time毫秒。和sleep不同的是,如果线程退出,wait会返回。
线程状态
bool isFinished() const
线程是否结束
bool isRunning() const
线程是否正在运行
线程优先级
void setPriority(Priority priority)
设置正在运行线程的优先级。如果线程没有运行,此函数不执行任何操作并立即返回。使用的start()来启动一个线程具有特定的优先级。优先级参数可以是QThread::Priority枚举除InheritPriortyd的任何值。
枚举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 | 使用和创建线程同样的优先级. 这是默认值 |
class WorkerThread : public QThread { Q_OBJECT 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()的新线程中,这意味着所有线程的queued slots将在旧线程中执行。
采取合理的措施来优雅地结束线程,一般思路:
发起线程退出操作,调用quit()或exit()。
等待线程完全停止,删除创建在堆上的对象。
适当的使用wait()(用于等待线程的退出)和合理的算法。
#include <QThread> #include <QMutexLocker> class WorkerThread : public QThread { Q_OBJECT public: explicit WorkerThread(QObject *parent = 0) : QThread(parent), m_bStopped(false) { qDebug() << "Worker Thread : " << QThread::currentThreadId(); } ~WorkerThread() { quit(); wait(); } void stop() { qDebug() << "Worker Stop Thread : " << QThread::currentThreadId(); QMutexLocker locker(&m_mutex); m_bStopped = true; } protected: virtual void run() Q_DECL_OVERRIDE { qDebug() << "Worker Run Thread : " << QThread::currentThreadId(); int nValue = 0; while (nValue < 100) { // 休眠50毫秒 msleep(50); ++nValue; // 准备更新 emit resultReady(nValue); // 检测是否停止 { QMutexLocker locker(&m_mutex); if (m_bStopped) break; } // locker超出范围并释放互斥锁 } } signals: void resultReady(int value); private: bool m_bStopped; QMutex m_mutex; };
当主线程调用stop()更新m_bStopped的时候,run()函数也极有可能正在访问它(这时,他们处于不同的线程),所以存在资源竞争,因此需要加锁,保证共享数据的安全性。
主线程会调用deleteLater,然后自动调用析构函数!
相关文章推荐
- Qt下QThread用法学习之多线程
- [Qt C++] QThread的正确用法
- QT QTableView用法小结
- C++ 实现类似Qt和Java的线程用法
- QT 中如何正确使用QThread
- Qt之线程(QThread)
- QT QStringList 用法
- Qt5.9中int转QString用法(函数QString::number)
- Qt 线程基础(QThread、QtConcurrent等) 2
- 【转】Qt多线程操作界面---在QThread更新QProgressBar
- Qt中两种定时器用法
- QT中的setAttribute()用法
- Qt编程—去掉标题栏和设置窗口透明用法
- QT StandardButton 等提示框 警告栏 的 用法
- QT5 QThread
- Qt QSpinBox 和QSlider用法 笔记(持续更新中)
- QT signal & slot 定义及用法 .
- Qt自总结(一) QThread
- QT QTableWidget 用法总结
- Qt Qtableview 的一些用法 希望共同学习探讨