Qt之QThread
简述
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(),操作系统将根据优先级参数调度线程。如果线程已经在运行,那么这个函数什么也不做。优先级参数的效果取决于操作系统的调度策略。特别是那些不支持线程优先级的系统优先级将会被忽略(例如在Linux中,更多细节请参考http://linux.die.net/man/2/sched_setscheduler)。
- void start(Priority priority = InheritPriority) [slot]
线程执行
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 terminate() [slot]
终止线程,线程可能会立即被终止也可能不会,这取决于操作系统的调度策略,使用terminate()之后再使用QThread::wait(),以确保万无一失。当线程被终止后,所有等待中的线程将会被唤醒。
警告:此函数比较危险,不鼓励使用。线程可以在代码执行的任何点被终止。线程可能在更新数据时被终止,从而没有机会来清理自己,解锁等等。。。总之,只有在绝对必要时使用此函数。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
线程是否正在运行
bool isInterruptionRequested() const
如果线程上的任务运行应该停止,返回true。可以使用requestInterruption()请求中断。
此函数可用于使长时间运行的任务干净地中断。从不检查或作用于该函数返回值是安全的,但是建议在长时间运行的函数中经常这样做。注意:不要过于频繁调用,以保持较低的开销。
void long_task() {
forever {
if ( QThread::currentThread()->isInterruptionRequested() ) {
return;
}
}
}
线程优先级
- void setPriority(Priority priority)
设置正在运行线程的优先级。如果线程没有运行,此函数不执行任何操作并立即返回。使用的start()来启动一个线程具有特定的优先级。优先级参数可以是QThread::Priority枚举除InheritPriortyd的任何值。
- void setPriority(Priority priority)
枚举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 | 使用和创建线程同样的优先级. 这是默认值 |
使用方式
worker-object
可以使用worker-object通过QObject::moveToThread将它们移动到线程中。
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
// 这里是昂贵的或阻塞的操作
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槽中的代码将在一个单独的线程中执行,然而,可以自由地将Worker的槽函数连接到任何信号(来自任何对象、在任何线程中),在不同的线程里连接信号和槽也是安全的,这要归功于一个名为Qt::QueuedConnection的连接机制。
子类化QThread
另一种使代码运行在一个单独的线程中的方法,是子类化QThread中并重新实现的run()函数。
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将在旧线程中执行。因此,如果要在新线程调用槽函数必须使用worker-object方法,新的槽函数不应直接在子类化QThread中来实现。
当子类化QThread时,谨记构造函数在旧线程中执行,然而run()在新线程中执行。如果一个成员变量的访问来自两个函数,然后从两个不同的线程访问变量,需要检查这样做是否安全。
注意:用在不同的线程中的对象进行交互时必须小心。详见同步线程(Synchronizing Threads)。
耗时操作
- requestInterruption()
- isInterruptionRequested()
请参考:Qt之模型/视图(自定义进度条)
Qt之QThread的更多相关文章
- Qt之QThread(深入理解)
简述 为了让程序尽快响应用户操作,在开发应用程序时经常会使用到线程.对于耗时操作如果不使用线程,UI界面将会长时间处于停滞状态,这种情况是用户非常不愿意看到的,我们可以用线程来解决这个问题. 前面,已 ...
- 解析Qt中QThread使用方法
本文讲述的是在Qt中QThread使用方法,QThread似乎是很难的一个东西,特别是信号和槽,有非常多的人(尽管使用者本人往往不知道)在用不恰当(甚至错误)的方式在使用QThread,随便用goog ...
- Qt线程QThread简析(8个线程等级,在UI线程里可调用thread->wait()等待线程结束,exit()可直接退出线程,setStackSize设置线程堆栈,首次见到Qt::HANDLE,QThreadData和QThreadPrivate)
QThread实例代表一个线程,我们可以重新实现QThread::run(),要新建一个线程,我们应该先继承QThread并重新实现run()函数. 需要注意的是: 1.必须在创建QThread对象之 ...
- Qt多线程-QThread
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt多线程-QThread 本文地址:http://techieliang.com/2 ...
- Qt之QThread随记
这是一篇随记,排版什么的就没有那么好了:) 首先要知道,一个线程在资源分配完之后是以某段代码为起点开始执行的,例如STL内的std::thread,POSIX下的pthread等,都是以函数加其参数之 ...
- Qt线程—QThread的使用--run和movetoThread的用法
Qt使用线程主要有两种方法: 方法一:继承QThread,重写run()的方法 QThread是一个非常便利的跨平台的对平台原生线程的抽象.启动一个线程是很简单的.让我们看一个简短的代码:生成一个在线 ...
- QT下QThread学习(二)
学习QThread主要是为了仿照VC下的FTP服务器写个QT版本.不多说,上图. FTP服务器的软件结构在上面的分析中就已经解释了,今天要解决的就是让每一个客户端的处理过程都可以按一个线程来单独跑.先 ...
- 【QT】 QThread部分源码浅析
本文章挑出QThread源码中部分重点代码来说明QThread启动到结束的过程是怎么调度的.其次因为到了Qt4.4版本,Qt的多线程就有所变化,所以本章会以Qt4.0.1和Qt5.6.2版本的源码来进 ...
- 【QT】QThread源码浅析
本章会挑出QThread源码中部分重点代码来说明QThread启动到结束的过程是怎么调度的.其次因为到了Qt4.4版本,Qt的多线程就有所变化,所以本章会以Qt4.0.1和Qt5.6.2版本的源码来进 ...
随机推荐
- BeanUtils(前端赋值给后台,忽略空属性)
package com.drn.core.util; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; im ...
- 异常值(outlier)
简介 在数据挖掘的过程中,我们可能会经常遇到一些偏离于预测趋势之外的数据,通常我们称之为异常值. 通常将这样的一些数据的出现归为误差.有很多情况会出现误差,具体的情况需要就对待: 传感器故障 -> ...
- thinkphp 同一字段不同查询条件实现
搞定了 另外区间查询还可以支持更多的条件,只要是针对一个字段的条件都可以写到一起,例如:$map['name'] = array(array('like','%a%'), array('like',' ...
- 【codeforces 799D】Field expansion
[题目链接]:http://codeforces.com/contest/799/problem/D [题意] 给你长方形的两条边h,w; 你每次可以从n个数字中选出一个数字x; 然后把h或w乘上x; ...
- LaTeX 基本的公式符号命令
本系列文章由 @YhL_Leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50240237 下面列出一些基本的LaT ...
- Android内存优化之封装九宫格
随着市场上越来越多的APP上线,好多软件对手机的内存要求也是很大,所以我们在开发的时候一定要掌握如何去优化内存,将自己的APP尽可能优化.今天我们就一起看一下九宫格的优化.下面是软件的截图 1.为了达 ...
- lucene构建restful风格的简单搜索引擎服务
来自于本人博客: lucene构建restful风格的简单搜索引擎服务 本人的博客如今也要改成使用lucene进行全文检索的功能,因此在这里把代码贴出来与大家分享 一,文件夹结构: 二,配置文件: 总 ...
- Leetcode_num1_Single Number
好久没有做题啦.从今天開始刷Leetcode的题.希望坚持的时间能长一点. 先从ac率最高的Single Number開始吧. 题目: Given an array of integers, ever ...
- How to get the MouseEvent coordinates for an element that has CSS3 Transform?
I want to detect where a MouseEvent has occurred, in coordinates relative to the clicked element. Wh ...
- Darwin流媒体server在windows下搭建
简单介绍 主页: http://dss.macosforge.org/ Darwin Streaming Server (DSS) is an open sourceproject intende ...