Qt那点事儿(一)
原文http://www.cnblogs.com/andreitang/archive/2011/08/03/2125815.html
第一回 Signal和Slot是同步的还是异步的?
我们知道Qt以他的signal和slot机制独步天下。但大家在用的时候有没有注意过,signal和slot之间是异步的,还是同步的呢?为此我问过不少使用Qt的道友。有人说是同步的,有人说是异步的,也有人说要看当时你的人品。:( #$%^&*
为此贫道,特别做了以下几个测试:
First,在main()主函数里,设置两个基于QObject为父类的对象a和b,a触发signal,b接受signal。请看具体案例:

1 class MyTestA : public QObject
2 {
3 Q_OBJECT
4 public:
5 void emitSignal()
6 {
7 signalMyTestA();
8 }
9
10 public slots:
11 void slotMyTestA()
12 {
13 qDebug()<<"slotMyTestA is called.";
14 }
15 signals:
16 void signalMyTestA();
17 };
18
19 class MyTestB : public QObject
20 {
21 Q_OBJECT
22 public slots:
23 void slotMyTestB()
24 {
25 qDebug()<<"slotMyTestB is called.";
26 }
27 signals:
28 void signalMyTestB();
29 };
30
31 int main(int argc, char *argv[])
32 {
33 QApplication app(argc, argv);
34
35 MyTestA a;
36 MyTestB b;
37 QObject::connect(&a,SIGNAL(signalMyTestA()),&b,SLOT(slotMyTestB()));
38
39 a.emitSignal();
40
41 return app.exec();
42 }

在slotMyTestB的函数里打个断点,看一下调用堆栈(call stack)。
是同步调用的,某些道友开始拈胡微笑,实践出真知啊。

此时只见东方黑云滚滚,电闪雷鸣,又有道友开始度劫了。突然一度劫道友横眉冷对,拿起拂尘刷刷的改写了上面的代码。只见此道友把a对象挪到了一个新线程中(MyTestC创建的),而b对象仍然在主线程中。然后a对象触发信号。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
class MyTestA : public QObject{ Q_OBJECTpublic: void emitSignal() { signalMyTestA(); }public slots: void slotMyTestA() { qDebug()<<"slotMyTestA is called."; }signals: void signalMyTestA();};class MyTestB : public QObject{ Q_OBJECTpublic slots: void slotMyTestB() { qDebug()<<"slotMyTestB is called."; }signals: void signalMyTestB();};extern MyTestB *g_pMyTestB;class MyTestC : public QThread{ Q_OBJECTpublic: void run() { MyTestA a; connect(&a,SIGNAL(signalMyTestA()),g_pMyTestB,SLOT(slotMyTestB())); a.emitSignal(); exec(); }public slots: void slotMyTestC() { qDebug()<<"slotMyTestC is called."; }signals: void signalMyTestC();};class MyTest : public QDialog{ Q_OBJECTpublic: MyTest(QWidget *parent = 0, Qt::WFlags flags = 0); ~MyTest();private: Ui::MyTestClass ui;};////////////////////////////////////////////////MyTestB *g_pMyTestB = NULL;int main(int argc, char *argv[]){ QApplication app(argc, argv); MyTestB b; g_pMyTestB = &b; MyTestC c; c.start(); return app.exec();} |
说时迟,那时快。在一道紫雷劈下之际,按下了F5。只见,此时的调用堆栈显示,

奇迹出现了,居然变成异步调用了。只见东方天空万道金光射下,在阵阵仙乐声中,传来朗朗之声:"贫道尘事已了,再无牵挂"。
难道Qt真的是靠人品的,或者Qt莫不是也是修仙道友,不日也将飞升。
在吾等众人膜拜加疑惑之时,只见飞升前辈,留下一条偈语。内事不决问百度,外事不决问谷歌。
吾等众人立刻搜寻,恍然大物。
原来signal和slot是异步调用还是同步调用,取决于对connect的设定。其实connect还有一个参数(Qt::ConnectionType),是它决定了是同步还是异步。以下是ConnectionType的定义

只不过,平常它有一个默认值Qt::AutoConnection,我们忽略了它。这时有道友问道,为何在AutoConnection模式下,有时是同步,有时是异步,莫非Auto就是人品代名词。
非也,其实Auto是这样规定的,
当sender和receiver在同一线程时,就是同步模式,而在不同线程时,则是异步模式。
众人皆曰善。
就在众人弹冠相庆之时,突然一道类似眼镜发出的寒光闪过,一个黑影渐渐清晰了起来。
他居然就是..................
青春永驻,十二年如一日的柯南君,他招牌式的磁性声音给众道友一晴天霹雳,“诸位以为这就是全部的真相吗?”
接着他刷刷的又改写了代码,在主线程中生成a,b两个对象,而a对象在新线程(MyTestC创建的)中触发信号。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
class MyTestA : public QObject{ Q_OBJECTpublic: void emitSignal() { signalMyTestA(); }public slots: void slotMyTestA() { qDebug()<<"slotMyTestA is called."; }signals: void signalMyTestA();};class MyTestB : public QObject{ Q_OBJECTpublic slots: void slotMyTestB() { qDebug()<<"slotMyTestB is called."; }signals: void signalMyTestB();};extern MyTestB *g_pMyTestB;extern MyTestA *g_pMyTestA;class MyTestC : public QThread{ Q_OBJECTpublic: void run() { g_pMyTestA->emitSignal(); exec(); }public slots: void slotMyTestC() { qDebug()<<"slotMyTestC is called."; }signals: void signalMyTestC();};/////////////////////////////////////////////MyTestB *g_pMyTestB = NULL;MyTestA *g_pMyTestA = NULL;int main(int argc, char *argv[]){ QApplication app(argc, argv); MyTestA a; g_pMyTestA = &a; MyTestB b; g_pMyTestB = &b; QObject::connect(&a,SIGNAL(signalMyTestA()),&b,SLOT(slotMyTestB())); MyTestC c; c.start(); return app.exec();} |
在众人疑惑的眼光中,此君淡定的按下了F5。只见调用堆栈(call stack)显示

众人皆惊呼,“Impossible”。a和b明明是属于一个线程的,为何会异步调用。此时我们熟悉的语录,又在耳边回响,是"我相信真相只有一个!!!"这句话吗?No,只见柯南君,优雅地挥了挥手指,"Nothing impossible",从口中缓缓滑出。
。众人皆扑街,“有屁快放”。
此时柯南君缓缓从口袋中,摸出一张纸,抛向空中,然后转身离去。只见随风飘落的纸面上面摘录了这么一段Qt源代码,在Auto模式下,如果要同步调用,不仅要求sender和receiver是同一线程,而且sender触发的时候,所在的线程也要和receiver一致。
|
1
2
3
4
5
6
7
8
9
10
11
12
|
// determine if this connection should be sent immediately or // put into the event queue if ((c->connectionType == Qt::AutoConnection && (currentThreadData != sender->d_func()->threadData || receiver->d_func()->threadData != sender->d_func()->threadData)) || (c->connectionType == Qt::QueuedConnection)) { queued_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv); continue; } else if (c->connectionType == Qt::BlockingQueuedConnection) { blocking_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv); continue; }<br><br>摘自qobject.cpp |
z众人皆惊,原来在Auto模式下,如果sender的触发时所处的线程和receiver不同,也会是异步调用。此时道友齐声向柯南喊道“这是全部的真相了吗”?柯南转过头来笑而不语,渐渐又消失在黑暗中。“有多少无耻可以重来”漂上了众人的心头。望着远处的雨后阳光,一个大大的问号也出现在众人头顶,"Qt你到底有多无耻???"。众人又陷入了沉思。
欲知后事如何,请听下回分解。
Qt那点事儿(一)的更多相关文章
- Qt那点事儿(三) 论父对象与子对象的关系
第三回 父与子 70后的道友都应该看过这么一部片子叫做<<父子情深>>.讲述的是一个小男孩患了绝症,父亲为了满足他的愿望,让已关门的游乐园为他们父子俩重新开放.在游乐园尽情地玩 ...
- Qt之QAbstractItemView视图项拖拽(二)
一.需求说明 上一篇文章Qt之QAbstractItemView视图项拖拽(一)讲述了实现QAbstractItemView视图项拖拽的一种方式,是基于QDrag实现的,这个类是qt自己封装好了的,所 ...
- Qt Quick 事件处理之信号与槽
前面两篇文章<QML 语言基础>和<Qt Quick 简单教程>中我们介绍了 QML 语言的基本的语法和 Qt Quick 的常见元素,亲们,通过这两篇文章,您应该已经能够完毕 ...
- Qt 格式化字符串
Qt字符串格式化性能比较 Qt字符串格式方法有三种, QString::arg(), QString::sprinft()和QStringList::join().今天我做了个简单的性能测试, 希望对 ...
- Windows下OpenCV 3.1.0 在 Qt Creator 4.0.2 (Qt 5.7.0 MinGW) 中的开发环境配置
2017-2-23 Update: 修改并添加了部分细节 最近正在学习OpenCV ,为毕业设计做准备.Windows版本的OpenCV都默认提供对VS的支持,其在VS中的配置比较简单,网上也有大批教 ...
- Qt Quick之StackView具体解释(1)
Qt Quick中有个StackView.我在<Qt Quick核心编程>一书中没有讲到.近期有人问起,趁机学习了一下,把它的基本使用方法记录下来. 我准备分两次来讲.第一次讲主要的使用方 ...
- Qt Quick综合实例之文件查看器
假设你基于Qt SDK 5.3.1来创建一个Qt Quick App项目,项目模板为你准备的main.qml文档的根元素是ApplicationWindow或Window.这次我们就以Applicat ...
- 公布Qt Widgets桌面应用程序的方法
公布Qt Widgets桌面应用程序的方法 Qt是一款优秀的跨平台开发框架,它能够在桌面.移动平台以及嵌入式平台上执行.眼下Qt 5介绍程序公布的文章帖子比較少.大家又很想要知道怎样公布Qt应用程序, ...
- Qt Quick 事件处理之信号与槽(foruok的博客)
前面两篇文章<QML 语言基础>和<Qt Quick 简单教程>中我们介绍了 QML 语言的基本语法和 Qt Quick 的常见元素,亲们,通过这两篇文章,您应该已经可以完成简 ...
随机推荐
- vue 查看dist文件里的结构
场景:优化打包后的代码,提高性能. 1.方式一:report-json. 1.1 package.json文件里加入以下命令, "report": "vue-cli-se ...
- 封装 axios
大家是否有印象,在开发项目中,我们往往会把axios给封装起来,写在一个js文件夹里,最后引入的也是js文件夹,而不是直接对axios进行操作,那为什么? 1. 如果一个组件需要请求数据,就要用到ax ...
- MySql快速入门(四)
在之前我们对MySql已经有了基本的了解,接下来我们就来接触MySql的分库分表,请往下阅读: 分库分表之MyCat实现 分库分表介绍: 随着微服务这种架构的兴起,我们应用从一个完整的大的应用,切分为 ...
- shell-删除指定时间前的文件
需要配合find和rm两个命令完成 显示20分钟前的文件: find /home/prestat/bills/test -type f -mmin +20 -exec ls -l {} \; 删除20 ...
- win10子系统ubuntu内的nginx启动问题
需用sudo启动,密码是windows密码.
- loj6278 数列分块入门题2
题意:支持区间加,询问区间中元素排名 维护两个域.一个域维护原序列,一个域维护快内排序序列. 每次修改后更新快内排序序列. 修改时O(sqrt(n)log(sqrt(n))) 询问时O(sqrt(n) ...
- Linux环境C语言斐波拉切数列(1,1,2,3,5,8,13,.........)实现
斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一 ...
- Linux断网安装jdk1.8
1.创建目录存放jdk包 mkdir /usr/java 2.上传jdk包 通过xftp或者其他远程工具 3.解压jdk tar zxvf jdk-8u221-linux-x64.tar.gz 4.打 ...
- could not parse as expression: "/login" (template: "include/include" - line 32, col 42)
<li><a href="login.html" th:href="/login">登录</a></li> or ...
- 跨站点脚本攻击XSS
来源:http://www.freebuf.com/articles/web/15188.html 跨站点脚本攻击是一种Web应用程序的攻击,攻击者尝试注入恶意脚本代码到受信任的网站上执行恶意操作.在 ...