【Qt开发】QThread介绍
回顾Qt之线程(QThread),里面讲解了如何使用线程,但还有很多人留言没有看明白,那么今天我们来一起瞅瞅关于QThread管理线程的那些事儿。。。
1、线程启动
void start(Priority
priority = InheritPriority)
调用后会执行run()函数,但在run()函数执行前会发射信号started(),操作系统将根据优先级参数调度线程。如果线程已经在运行,那么这个函数什么也不做。优先级参数的效果取决于操作系统的调度策略。特别是那些不支持线程优先级的系统优先级将会被忽略(例如在Linux中,更多细节请参考http://linux.die.net/man/2/sched_setscheduler)。
2、线程执行
int exec()
进入事件循环并等待直到调用exit(),返回值是通过调用exit()来获得,如果调用成功则范围0。
virtual void run();
线程的起点,在调用start()之后,新创建的线程就会调用这个函数,默认实现调用exec(),大多数需要重新实现这个功能,便于管理自己的线程。该方法返回时,该线程的执行将结束。
3、线程退出
void quit()
告诉线程事件循环退出,返回0表示成功,相当于调用了QThread::exit(0)。
void exit(int
returnCode = 0)
告诉线程事件循环退出。
调用这个函数后,线程离开事件循环后返回,QEventLoop::exec()返回returnCode,
按照惯例0表示成功,任何非0值表示失败。
void terminate()
终止线程,线程可能会立即被终止也可能不会,这取决于操作系统的调度策略,使用terminate()之后再使用QThread::wait()确保万无一失。
当线程被终止后,所有等待中的线程将会被唤醒。
警告:此功能比较危险,不鼓励使用。线程可以在代码执行的任何点被终止。线程可能在更新数据时被终止,从而没有机会来清理自己,解锁等等。。。总之,只有在绝对必要时使用此功能。
建议:一般情况下,都在run函数里面设置一个标识符,可以控制循环停止。然后才调用quit函数,退出线程。
4、线程等待
void msleep(unsigned
long msecs)
强制当前线程睡眠msecs毫秒
void sleep(unsigned
long secs)
强制当前线程睡眠secs秒
void usleep(unsigned
long usecs)
强制当前线程睡眠usecs微秒
bool wait(unsigned long time = ULONG_MAX);
线程将会被阻塞,等待time毫秒。和sleep不同的是,如果线程退出,wait会返回。
5、线程状态
bool isFinished() const
线程是否结束
6、线程优先级
priority)
const
Constant |
Value |
Description |
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 |
使用和创建线程同样的优先级. 这是默认值. |
在Qt之线程(QThread)一节中我介绍了QThread
的两种使用方法:
1、子类化
QThread(不使用事件循环)。
这是官方手册、例子以及相关书籍中都介绍的一种常用的方法。
a. 子类化 QThread
b. 重载 run 函数,run函数内有一个while或for的死循环(模拟耗时操作)
c. 设置一个标记为来控制死循环的退出。
2、子类化 QObject
a. 子类化 QObject
b. 定义槽函数
c. 将该子类的对象moveToThread到新线程中
run 对于线程的作用相当于main函数对于应用程序。它是线程的入口,run的开始和结束意味着线程的开始和结束。
采用这两种做法,毫无疑问都会在次线程中运行(这里说的是,run中的逻辑以及子类化QObject后连接通过moveToThread然后连接到QThread的started()信号的槽函数,这个下面会详细讲解)。
那么,线程中的槽函数是怎么运行的呢?
说到信号与槽,大家应该再熟悉不过了,包括我,特别喜欢使用自定义信号与槽,感觉用起来特方便、特棒。。。
经常使用,你能否100%的使用正确?你了解它的高级用法吗?
1、你是否在多次connect,还发现不了为什么槽函数会执行那N多次。
2、你是否了解disconnect
3、你是否了解connect中的第五个参数 Qt::ConnectionType
关于connect、disconnect信号、槽的使用可参考:Qt之信号与槽。既然谈到线程这里需要重点说下Qt::ConnectionType(信号与槽的传递方式)
Constant |
Value |
Description |
Qt::AutoConnection |
0 |
自动连接:(默认值)如果信号在接收者所依附的线程内发射,则等同于直接连接。如果发射信号的线程和接受者所依附的线程不同,则等同于队列连接。 |
Qt::DirectConnection |
1 |
直接连接:当信号发射时,槽函数将直接被调用。无论槽函数所属对象在哪个线程,槽函数都在发射信号的线程内执行。 |
Qt::QueuedConnection |
2 |
队列连接:当控制权回到接受者所依附线程的事件循环时,槽函数被调用。槽函数在接收者所依附线程执行。也就是说:这种方式既可以在线程内传递消息,也可以跨线程传递消息 |
Qt::BlockingQueuedConnection |
3 |
与Qt::QueuedConnection类似,但是会阻塞等到关联的slot都被执行。这里出现了阻塞这个词,说明它是专门用来多线程间传递消息的。 |
举例:
MyObject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H #include class MyObject : public QObject
{
Q_OBJECT public:
explicit MyObject(QObject *parent = 0); public slots:
void start();
}; #endif // MYOBJECT_H
MyObject.cpp
#include "MyObject.h"
#include
#include MyObject::MyObject(QObject *parent)
: QObject(parent)
{ } void MyObject::start()
{
qDebug() << QString("my object thread id:") << QThread::currentThreadId();
}
main.cpp
#include "MyObject.h"
#include
#include
#include int main(int argc, char *argv[])
{
QApplication a(argc, argv); qDebug() << QString("main thread id:") << QThread::currentThreadId(); MyObject object;
QThread thread;
object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()));
thread.start(); return a.exec();
}
"main thread id:" 0xf08
"my object thread id:" 0x216c
显然主线程与槽函数的线程是不同的(你可以多次尝试,屡试不爽。。。),因为moveToThread后MyObject所在的线程为QThread,继上面介绍的thread.start()执行后首先会发射started()信号,也就是说started()信号发射是在次线程中进行的,所以无论采取Qt::AutoConnection、Qt::DirectConnection、Qt::QueuedConnection哪种连接方式,主线程与槽函数的线程都是不同的。
1、修改代码如下:
MyObject object;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::DirectConnection);
thread.start();
"main thread id:" 0x2688
"my object thread id:" 0x2110
显然主线程与槽函数的线程是不同的,MyObject所依附的线程为主线程(因为注释掉了moveToThread),继上面介绍的Qt::DirectConnection(无论槽函数所属对象在哪个线程,槽函数都在发射信号的线程内执行)。也就是说started()信号发射是在次线程中进行的,槽函数也是在次线程中进行的,所以主线程与槽函数的线程是不同的。
2、修改代码如下:
MyObject object;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::QueuedConnection);
thread.start();
查看运行结果:
"main thread id:" 0x24ec
"my object thread id:" 0x24ec
显然主线程与槽函数的线程是相同的,继上面介绍的Qt::QueuedConnection(槽函数在接收者所依附线程执行)。也就是说started()信号发射是在次线程中进行的,但MyObject所依附的线程为主线程(因为注释掉了moveToThread),所以主线程与槽函数的线程必然是相同的。
3、修改代码如下:
MyObject object;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::AutoConnection);
thread.start();
"main thread id:" 0x2700
"my object thread id:" 0x2700
显然主线程与槽函数的线程是相同的,MyObject所依附的线程为主线程(因为注释掉了moveToThread),继上面介绍的Qt::AutoConnection(如果信号在接收者所依附的线程内发射,则等同于直接连接。如果发射信号的线程和接受者所依附的线程不同,则等同于队列连接。)。因为started()信号和MyObject依附的线程不同,所以结果和Qt::QueuedConnection对应的相同,所以主线程与槽函数的线程是相同的。
基本就介绍到这里,QThread使用和上面的大同小异,run里面执行的代码都是在次线程中,如果是QThead的槽函数,那么结论同上!
【Qt开发】QThread介绍的更多相关文章
- 【应用笔记】【AN005】Qt开发环境下基于RS485的4-20mA电流采集
简介 4-20mA电流环具有广泛的应用前景,在许多行业中都发挥着重要作用.本文主要介绍在Qt开发环境下基于RS485实现4-20mA电流采集,实现WINDOWS平台对数据的采集.分析及显示. 系统组成 ...
- 【Qt开发】QThread 实用技巧、误区----但文档中没有提到
本文主要内容: 在任务一中,用 四 种方式实现:点击界面按钮,开线程运行一段程序,结果显示在一个Label上.1. 用不正确的方式得到看似正确的结果2. 用Qt Manual 和 例子中使用的方法3. ...
- Qt开发技术:QCharts(三)QCharts样条曲线图介绍、Demo以及代码详解
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- Qt开发技术:图形视图框架(一)基本介绍
前话 使用到Qt的视图框架. Qt视图框架介绍 简介 图形视图框架(The Graphic View Framework)用于管理和与大量定制的二维图形项目交互,以及用于可视化项目的视图小 ...
- Qt之QThread随记
这是一篇随记,排版什么的就没有那么好了:) 首先要知道,一个线程在资源分配完之后是以某段代码为起点开始执行的,例如STL内的std::thread,POSIX下的pthread等,都是以函数加其参数之 ...
- Qt之QThread(深入理解)
简述 为了让程序尽快响应用户操作,在开发应用程序时经常会使用到线程.对于耗时操作如果不使用线程,UI界面将会长时间处于停滞状态,这种情况是用户非常不愿意看到的,我们可以用线程来解决这个问题. 前面,已 ...
- 解析Qt中QThread使用方法
本文讲述的是在Qt中QThread使用方法,QThread似乎是很难的一个东西,特别是信号和槽,有非常多的人(尽管使用者本人往往不知道)在用不恰当(甚至错误)的方式在使用QThread,随便用goog ...
- QT开发环境安装配置教程
QT开发环境安装配置教程 分类: QT2012-11-29 23:31 35366人阅读 评论(12) 收藏 举报 Linux版的直接在ubutnu软件中心输入QT,安装响应的Designer,Cre ...
- QT开发环境搭建
一.Qt发展史 1991年,由奇趣科技开发的跨平台C++图形用户界面应用程序开发框架: 2008年,Nokia从Trolltech公司收购Qt, 并增加LGPL的授权模式: 2011年,Digia从N ...
- Qt多线程-QThread
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt多线程-QThread 本文地址:http://techieliang.com/2 ...
随机推荐
- 如何在Linux下安装Tomcat
上篇文章写到了Linux下安装JDK1.8,这篇文章详细阐述一下 如何在Linux下安装Tomcat!!!有啥问题可以留言,博主每天都会看博客的. 准备步骤和方法和以前一样,博主用的工具是XShell ...
- bootstrap-table.min.js不同版本返回分页参数不同的问题
1.使用公司用的bootstrap-table.min.js ,刚开始bootstrap-table分页参数是这么写的 分页查询参数: 后端代码为: Result返回类的参数为list,以及total ...
- Python之网络编程之并发编程的IO模型,
了解新知识之前需要知道的一些知识 同步(synchronous):一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行 #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调 ...
- iOS自定义键盘的简单实现
自定义键盘类VolumeInputKeyboardView: VolumeInputKeyboardView.h文件: #import <UIKit/UIKit.h> NS_ASSUME_ ...
- springboot扫描自定义的servlet和filter代码详解_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 这几天使用spring boot编写公司一个应用,在编写了一个filter,用于指定编码的filter,如下: /** ...
- The Preliminary Contest for ICPC Asia Shanghai 2019 L. Digit sum
题目:https://nanti.jisuanke.com/t/41422 思路:预处理 #include<bits/stdc++.h> using namespace std; ][]= ...
- DevOps之持续集成Pipeline(一)
一.Pipeline介绍 Jenkins2.0中最大的一个特性就是Pipeline,实际使用中Pipeline已经超越了我们对jenkins本身的理解,可能在之前我们大多数把Jenkins当做 ...
- void 运算符和 逗号运算符
一.void 运算符 void 运算符的作用目的是 执行一个表达式,但是不用返回任何值,或者是返回undefined void 本身就有 无效.空的 的意思. void运算符的用法: 1.不加括号的写 ...
- 百分号编码(URL编码)
百分号编码又叫做URL编码,是一种编码机制,只要用于URI(包含URL和URN)编码中. URL中那些字符需要编码,又为什么进行编码 一.URL是什么? URL(Uniform Resource L ...
- 如何查看 mysql 的视图?
1.查询表(包括view) mysql> use iips; Database changed mysql> show tables; +------------------------- ...