Qt中连接到同一signal的多个slots的执行顺序问题

  • in the order they have been connected

起源

前些天忘记在哪儿讨论过这个问题,今天在csdn又看到有网友问这个问题,而其他网友却无一例外的给出了“无序”这个答案。

Manual

Qt的问题,当manual中有明确文字说明时,我们应该以Qt的manual为准:

http://doc.qt.nokia.com/4.8/signalsandslots.html

If several slots are connected to one signal, the slots will be executed one after the other, in the order they have been connected, when the signal is emitted.

或者http://doc.qt.nokia.com/4.8/qobject.html

If a signal is connected to several slots, the slots are activated in the same order as the order the connection was made, when the signal is emitted.

恩,说的很明确,各个槽按照被connect的顺序被执行【注意,在队列模式时,是指相应的事件被post,仍不保证槽被按照该顺序执行】。

可是,为什么很多人认为是无序呢?(除了前面提及的,还有什么其他因素么?)

翻翻Qt4.5以及该版本之前的manual,可以看到

http://doc.qt.nokia.com/4.5/signalsandslots.html

If several slots are connected to one signal, the slots will be executed one after the other, in an arbitrary order, when the signal is emitted.

以及http://doc.qt.nokia.com/4.5/qobject.html

If a signal is connected to several slots, the slots are activated in an arbitrary order when the signal is emitted.

网络上以及书籍中的大部分资料都是Qt4.6之前的,故尔 ...

源码

恩,尝试看过元对象系统这部分源码的网友对这部分不会觉得陌生。如果没看过,可以瞅瞅这个Qt Meta Object system 学习(三)

  • QObject::connect() 最终将 信号和槽的索引值放置到一个Connection列表中

QObjectPrivate::Connection *c = new QObjectPrivate::Connection; 
    c->sender = s; 
    c->receiver = r; 
    c->method = method_index; 
    c->connectionType = type; 
    c->argumentTypes = types; 
    c->nextConnectionList = 0; 
QObjectPrivate::get(s)->addConnection(signal_index, c); 
  • 信号的发射,就是借助QMetaObject::activate() 来依次处理前面那个Connection列表总的项

do { 
        QObjectPrivate::Connection *c = connectionLists->at(signal_index).first; 
        if (!c) continue; 
        // We need to check against last here to ensure that signals added  
        // during the signal emission are not emitted in this emission. 
        QObjectPrivate::Connection *last = connectionLists->at(signal_index).last;
 
       do { 
            if (!c->receiver) 
                continue; 
             QObject * const receiver = c->receiver;

在该过程中:

  • 如果是直接连接,则通过 QMetaObject::metacall() 直接调用
  • 如果是队列连接,则post一个QMetaCallEvent事件,稍后通过事件派发,该事件的处理函数负责通过 QMetaObject::metacall() 调用相应的槽函数【注意,小心此时槽函数的执行顺序】

注意:此处的代码片段是Qt4的,而Qt5.0 中由于引入了新式的信号和槽语法,对应部分源码有较大变化。

参考


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值