Qt那点事儿(一)

第一回 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_OBJECT

public:

    void emitSignal()

    {

        signalMyTestA();

    }

public slots:

    void slotMyTestA()

    {

        qDebug()<<"slotMyTestA is called.";

    }

signals:

    void signalMyTestA();

};

class MyTestB : public QObject

{

    Q_OBJECT

public slots:

    void slotMyTestB()

    {

        qDebug()<<"slotMyTestB is called.";

    }

signals:

    void signalMyTestB();

};

extern MyTestB *g_pMyTestB;

class MyTestC : public QThread

{

    Q_OBJECT

public:

    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_OBJECT

public:

    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_OBJECT

public:

    void emitSignal()

    {

        signalMyTestA();

    }

public slots:

    void slotMyTestA()

    {

        qDebug()<<"slotMyTestA is called.";

    }

signals:

    void signalMyTestA();

};

class MyTestB : public QObject

{

    Q_OBJECT

public slots:

    void slotMyTestB()

    {

        qDebug()<<"slotMyTestB is called.";

    }

signals:

    void signalMyTestB();

};

extern MyTestB *g_pMyTestB;

extern MyTestA *g_pMyTestA;

class MyTestC : public QThread

{

    Q_OBJECT

public:

    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你到底有多无耻???"。众人又陷入了沉思。

欲知后事如何,请听下回分解。

  • 19
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一百编程网朱老师

谢谢大爷谢谢大爷谢谢大爷谢谢大

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值