Qt信号槽的一些事
注:此文是站在Qt5的角度说的,对于Qt4部分是不适用的。
1.先说Qt信号槽的几种连接方式和执行方式。
1)Qt信号槽给出了五种连接方式:
| Qt::AutoConnection | 0 | 自动连接:默认的方式。信号发出的线程和糟的对象在一个线程的时候相当于:DirectConnection, 如果是在不同线程,则相当于QueuedConnection |
| Qt::DirectConnection | 1 | 直接连接:相当于直接调用槽函数,但是当信号发出的线程和槽的对象不在一个线程的时候,则槽函数是在发出的信号中执行的。 |
| Qt::QueuedConnection | 2 | 队列连接:内部通过postEvent实现的。不是实时调用的,槽函数永远在槽函数对象所在的线程中执行。如果信号参数是引用类型,则会另外复制一份的。线程安全的。 |
| Qt::BlockingQueuedConnection | 3 | 阻塞连接:此连接方式只能用于信号发出的线程(一般是信号对象的线程) 和 槽函数的对象不在一个线程中才能用。通过信号量+postEvent实现的。不是实时调用的,槽函数永远在槽函数对象所在的线程中执行。但是发出信号后,当前线程会阻塞,等待槽函数执行完毕后才继续执行。 |
| Qt::UniqueConnection | 0x80 | 防止重复连接。如果当前信号和槽已经连接过了,就不再连接了。 |
2)信号槽的调用方式和线程:
UniqueConnection 模式:严格说不算连接方式,方式就是4种,此只是一个附加的参数。不讨论。
AutoConnection 模式:这个模式是默认的,但其可以看作是DirectConnection和QueuedConnection的自动选择,直接分析那两种也就行了。
发出信号,调用槽的方式也可以简单的分为两种:同步调用和异步调用
同步调用:发出信号后,当前线程等待槽函数执行完毕后才继续执行。
异步调用:发出信号后,立即执行剩下逻辑,不关心槽函数什么时候执行。
所以有下表:
| 线程/模式 | DirectConnection | QueuedConnection | BlockingQueuedConnection |
| 相同线程 | 直接调用,同步调用。 | 通过事件进行队列调用。异步调用. | 不可用 |
| 不同线程 | 直接调用。同步调用。槽函数在发出信号的线程执行。有线程安全隐患。 | 通过事件进行队列调用。异步调用.槽函数在对象所在的线程执行。线程安全。 | 通过事件进行阻塞调用。同步调用。槽函数在对象所在的线程执行。线程安全。 |
| Qt事件循环依赖 | 直接调用,不依赖Qt事件循环 | 通过事件进行队列调用。依赖,槽函数所在对象的线程必须启用Qt事件循环【注:(1)】 | 通过事件进行队列调用,用信号量实现阻塞。依赖,槽函数所在对象的线程必须启用Qt事件循环 |
注(1):事件循环一般用exec()函数开启。QApplicaion::exec()、QMessageBox::exec()都是事件循环。其中前者又被称为主事件循环
http://blog.chinaunix.net/uid-27685749-id-3847998.html
2.Qt信号连接多个槽,调用顺序。
先说基本原则:
槽函数开始调用的顺序和连接的顺序是一致的。
但是,上面也说了,有同步调用和异步调用。
对于同步调用,你观察的结果和基本原则一样。
但是对于异步调用,可能你最先连接的它,但是可能其他都执行完毕了,但是其还没执行。是因为对于异步调用:是开始调用的时候,生成一个需要调用这个函数的事件,然后放到事件队列里。然后立即返回,去执行调用其他函数或者槽函数,不关心槽函数的执行状态的。等到事件队列里任务轮到此事件再去调用。
3.信号的返回值。
大都说Qt信号槽不能使用返回值。其实不不准确的,Qt5中,信号槽是有返回值的(注:qt4也支持返回值)。只是Qt的一个信号可以连接多个槽,还有同步调用和异步调用的问题,没法支持的很好,所以,返回值虽有,但只是鸡肋。
先说下返回值的规则把:
- 同步调用才有返回值,异步调用的返回值永远为返回值类型默认构造函数出来的。(注:看来槽还是不要用返回值了)
- 连接的多个槽都返回值,那么结果是最后调用(连接)的那个。
也就是说对于QueuedConnection连接的信号槽,永远只是返回返回类型的默认构造函数的。对于AutoConnection连接的,如果发出信号的线程和槽函数线程不同亦然。
测试小例子地址:https://github.com/dushibaiyu/DsbyLiteExample/tree/master/QtSignalsSlotTest
4.信号参数的安全问题:
因为一个信号可以连接多个槽函数,如果参数是T * 或者是T &话会不会第一个槽函数改变参数的值,然后第二次调用的参数就已经不是信号发出的值?
1)对于T &: 在同步调用中则是变化的,不可用于异步,不可跨线程。所以BlockingQueuedConnection方式的同步也不行。(T& 不可用在队列调用(QueuedConnection)和阻塞调用(BlockingQueuedConnection)中。只能使用const T &)
因为同步调用,你可以理解成直接调用,那么连接多个槽函数就相当于直接连续调用多个函数。类似于:
// 函数原型都是:void (int &a )
int a;
fun1(a);
fun2(a)
····· // 函数原型都是:void (int * a )
int a;
pfun1(&a);
pfun2(&a)
·····
这样,当第一个函数执行改变参数值之后,其后的函数调用都要受影响。
2) 对于T *,最好不要同时连接多个槽。
对于同步调用:是一个接着一个调用的,执行顺序类似上面,所以值也是每次调用也会变化的。
对于异步调用:其内容确实不确定的,因为异步调用的时间是不可控的。如果还有跨线程相关,则还有线程安全问题。
5.信号槽性能损失:
注:仅仅代码层进行的理论分析,非实际测试,不严谨,不权威。
关于信号槽(很多吐槽Qt就是说的这个):
(1)Qt4语法的,都说是匹配字符串,其实只是链接信号槽的用的匹配字符串 的方法,通过字符串找到信号和槽在QMeatObject里存的索引位置int类型,还有槽函数的索引,然后调用的时候通过索引号用switch去区分的 发射的那个函数,然后取出对应的链接槽的list,循环检测槽函数的参数是否匹配,然后调用槽函数。。这个链接时会耗时查找,但是你能有多少信号?这个链 接也耗时不多,调用的时候耗时主要就是在参数匹配上了。
(2)Qt5 语法的,Qt5 的槽函数链接和执行是基于模板实现的,函数对象。信号和槽的参数问题是编译时检查的,执行效率更高,但是编译就慢点了。链接时也是通过信号的地址找到其的 信号索引,至于槽函数直接是生成一个函数对象的,然后调用的时候也是先switch找到发射的信号,取出list,然后逐个调用其储存的函数对象,所以对 于Qt5 语法的信号槽,调用性能损失几乎可以说无的。
(3)链接的信号槽的时候,Qt::UniqueConnection的链接方式会对已经链接过的此先好的槽函数进行遍历,会有链接时的损失。其他链接的损失就在上面说过了。
(3)在信号槽调用的时候,还有一些链接方式和线程的判断和为了安全问题的锁操作。关于这个就还涉及到调用槽函数的线程问题。
对于同线程直接调用,较函数对象直接调用的损失,就只有链接方式和线程的判断的几个if 分支和 锁的操作。
对于线程间通讯的调用,跨线程。信号槽内部也是通过Qt事件循环机制实现的,跨线程就不是时时调用了,主要是安全了,对于性能有没有损失没法评论的。对于跨线程阻塞的调用,这个也是事件实现,只是发射信号的线程会阻塞,这个找不到对应的直接调用的比较,也不好说。
关于信号槽Qt是作了很多方便使用和安全调用,较之函数指针,性能会有损失,但是也没损失多少的。对于函数对象调用,Qt5语法的调用,几乎是不损失什么的。
注:此文是个人根据文档,源码和自己写小例子测试得出的总结,如有错误请您指出。
转自:http://www.dushibaiyu.com/2015/07/qt-signals-slots-connect.html
Qt信号槽的一些事的更多相关文章
- Qt信号槽的一些事(第一次知道信号还有返回值,以及Qt::UniqueConnection)
注:此文是站在Qt5的角度说的,对于Qt4部分是不适用的. 1.先说Qt信号槽的几种连接方式和执行方式. 1)Qt信号槽给出了五种连接方式: Qt::AutoConnection 0 自动连接:默认的 ...
- Qt信号槽的一些事 Qt::带返回值的信号发射方式
一般来说,我们发出信号使用emit这个关键字来操作,但是会发现,emit并不算一个调用,所以它没有返回值.那么如果我们发出这个信号想获取一个返回值怎么办呢? 两个办法:1.通过出参形式返回,引用或者指 ...
- QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题——QT qRegisterMetaType 注册MetaType——关键:注册自定义数据类型或QMap等容器类
一般情况下信号槽直接连接方式不会出现问题,但是如果信号与槽在不同线程或Qt::QueuedConnection方式连接,可能会在连接期间报以下类似问题,如: QObject::connect: Can ...
- QT信号槽详解
1 QT信号槽详解 1.1 信号和槽的定义 信号是触发信号,例如按钮的点击触发一个clicked信号,槽是用来接收信号,并处理信号,相当于信号响应函数.一个信号可以关联多个槽函数,信 ...
- QT源码之Qt信号槽机制与事件机制的联系
QT源码之Qt信号槽机制与事件机制的联系是本文要介绍的内容,通过解决一个问题,从中分析出的理论,先来看内容. 本文就是来解决一个问题,就是当signal和slot的连接为Qt::QueuedConne ...
- Qt信号槽-原理分析
目录 一.问题 二.Moc 1.变量 2.Q_OBJECT展开后的函数声明 3.自定义信号 三.connect 四.信号触发 1.直连 2.队列连接 五.总结 六.推荐阅读 一.问题 学习Qt有一段时 ...
- Qt信号槽源码剖析(一)
大家好,我是IT文艺男,来自一线大厂的一线程序员 大家在使用Qt开发程序时,都知道怎么使用Qt的信号槽,但是Qt信号槽是怎么工作的? 大部分人仍然不知道:也就是说大家只知道怎么使用,却不知道基于什么原 ...
- Qt信号槽源码剖析(二)
大家好,我是IT文艺男,来自一线大厂的一线程序员 上节视频给大家讲解了Qt信号槽的基本概念.元对象编译器.示例代码以及Qt宏:今天接着深入分析,进入Qt信号槽源码剖析系列的第二节视频. Qt信号槽的宏 ...
- (文字版)Qt信号槽源码剖析(三)
大家好,我是IT文艺男,来自一线大厂的一线程序员 上节视频给大家讲解了Qt信号槽的Qt宏展开推导:今天接着深入分析,进入Qt信号槽源码剖析系列的第三节视频. Qt信号槽宏推导归纳 #define si ...
随机推荐
- 3DSMAX中英文对比大全(从A-Z分类)
A Absolute Mode Transform Type-in绝对坐标方式变换输入 Absolute/Relative Snap Toggle Mode绝对/相对捕捉开关模式 ACIS Optio ...
- 温故而知新: 关于 js Form 方式提交的一些新认知
这里介绍的是通过js进行异步form提交,而不是表单Form Submit提交. 提交方式主要有以下两种: 参数为字符串方式的提交,如:a=b&c=d formData方式提交, 如:new ...
- php 数组与数组 的交集和差集
注意,必须是第一个参数的数组的长度比较长才可以使用 $a1=array("0","1","2","3"); $a2=ar ...
- Mac - 使用php环境
按下shift + Command + G ,输入以下php(www)路径 /Library/WebServer/Documents 打开终端,输入以下命令打开环境 sudo apachectl s ...
- ev3dev:c语言开发lego ev3主机
有了ev3dev,真是一且皆有可能啊,最近,看到一个好人,居然做了一个ev3的c库. 激动中... 学习有目标了...,赶紧记录一下. https://github.com/theZiz/ev3c
- [k8s]dashboard1.8.1搭建( heapster1.5+influxdb+grafana)
dashboard最终效果 多了执行sh的窗口 heapster+influxdb+grafana搭建 整个架构是 dashboard去检测 hepster service服务, heapster通过 ...
- 【Android】18.1 利用安卓内置的定位服务实现位置跟踪
分类:C#.Android.VS2015: 创建日期:2016-03-04 一.安卓内置的定位服务简介 通常将各种不同的定位技术称为位置服务或定位服务.这种服务是通过电信运营商的无线电通信网络(如GS ...
- [转] 职业规划:一个老鸟眼中“IT民工”的发展方向
IT行业“挣钱太容易”,“IT不像政府管房产这么严,想干嘛就干嘛,另外都跑到境外去上市,没干两年市值翻好多倍,利润比地产高出几十倍几千倍,我们投入10块钱赚1块钱,IT行业投入10块钱赚1000块钱, ...
- angular学习笔记(八)-控制视图显示隐藏
本篇介绍angular控制视图的显示和隐藏: 通过给元素添加ng-show属性或者ng-hide属性来控制视图的显示或隐藏: ng-show: 绑定的数据值为true时,显示元素,值为false时,隐 ...
- Linux下crontab内环境变量与Shell环境变量的关系【转】
crontab,总是不会缺省的从用户profile文件中读取环境变量参数 经常导致在手工执行某个脚本时是成功的,但是到crontab中试图执行时就会报错. 解决办法如下: 方法一:在shell文件中获 ...