libjingle源码分析之一:Signal机制

  • 摘要

        本文主要分析了libjingle中的Signal(信号)机制,它实际上是基于sigslot开源库。本文开始描述了Signal机制是什么;然后,给出一个libjingle文档中的例子,来描述它是如何使用的。最后,介绍了Signal机制的具体实现。

  • 概述

        按照libjingle文档关于Signal(https://developers.google.com/talk/libjingle/important_concepts#signals)的介绍,Signal机制实际上采用的是sigslot开源库(http://sourceforge.net/projects/sigslot/?source=directory)。sigslot是一个开源的回调框架,它可以使得类之间的回调使用的简单化,下面是libjingle文档中对sigslot的描述。

        sigslot is a generic framework that enables you to connect a calling member to a receiving function in any class (including the same class) very simply.


        Signal机制的工作方式参见下图的描述。源中设置一个或多个信号,目标为了在源的信号触发时获获得通知,需要连接到信号上。可以有多个目标发起连接,也可以同一个目标发起多个连接。连接创建好之后,源触发信号时,目标A和目标B就可以收到信号触发的消息了。


  • 使用

        libjingle中,源和目标都是对象,目标对象的类必须继承于sigslot::has_slots,信号是源对象的成员变量,必须是sigslot::signal?类型,其中?代表参数的个数(支持0到8),比如要设置带两个参数的信号,那么就是类型sigslot::signal2。要注意的是,libjingle中所有的信号变量为了方便,名称都加了前缀Signal。在目标对象初始化的时候,需要通过sigslot::signal?的connect函数将目标对象上的回调函数连接到信号上。当源对象触发信号时,目标函数的对应的回调函数会被一次调用。需要注意的是,回调函数的参数类型和个数需要和sigslot::signal?申明的一样。
        Signal机制的使用很简单,下面是libjingle文档中的例子。Sender代表的是源,Sender中的SignalDanger代表的是信号,是sigslot::signal2类型的变量。Receiver代表的是目标,继承自sigslot::has_slots。Receiver的构造函数中,通过调用SignalDanger的connect函数,连接函数OnDanger到SignalDanger上,当Sender调用Panic函数触发信号SignalDanger时,会转调到Receiver::OnDanger函数中。

[cpp]  view plain copy
  1. // Class that sends the notification.  
  2. class Sender  {  
  3.   
  4.   // The signal declaration.   
  5.   // The '2' in the name indicates the number of parameters. Parameter types   
  6.   // are declared in the template parameter list.  
  7.   sigslot::signal2<string message, std::time_t time> SignalDanger;  
  8.   
  9.   // When anyone calls Panic(), we will send the SignalDanger signal.  
  10.   void Panic(){  
  11.     SignalDanger("Help!", std::time(0));   
  12.   }  
  13.    
  14.  // Listening class. It must inherit sigslot.  
  15. class Receiver : public sigslot::has_slots<>{  
  16.   
  17.   // Receiver registers to get SignalDanger signals.  
  18.   // When SignalDanger is sent, it is caught by OnDanger().  
  19.   // Second parameter gives address of the listener function class definition.  
  20.   // First parameter points to instance of this class to receive notifications.  
  21.   Receiver(Sender sender){   
  22.         sender->SignalDanger.connect(this, &Receiver.OnDanger);  
  23.   }  
  24.   
  25.   // When anyone calls Panic(), Receiver::OnDanger gets the message.  
  26.   // Notice that the number and type of parameters match  
  27.   // those in Sender::SignalDanger, and that it doesn't return a value.  
  28.   void OnDanger(string message, std::time_t time){  
  29.     if(message == "Help!")  
  30.     {   
  31.       // Call the police  
  32.       ...  
  33.     }  
  34.   }  
  35. ...  
  36. }  

  • 实现

        Signal机制的实现如下图所示。?代表的是0-8,sigslot::_connection类代表的是连接,其中包含了sigslot::has_slots对象和其中的回调函数地址。而sigslot::has_slots对象中则包含了所有连接的的sigslot::signal对象,这样的话可以在销毁时,断开和signal之间的连接。源码参见文件talk\base\sigslot.h。


        当调用signal的connect函数连接时,connect函数会创建_connection对象,然后将自己作为回调的发送者添加到has_slots中。

        类之间的继承关系如下图所示:


        SIGSLOT_DEFAULT_MT_POLICY是一个宏,定义如下。由于sigslot中的类,会对链表或集合进行操作,故SIGSLOT_DEFAULT_MT_POLICY只是增加了锁支持,若是单线程回调,则不需要锁。具体参见single_threaded和multi_threaded_local的实现。

[cpp]  view plain copy
  1. #ifndef SIGSLOT_DEFAULT_MT_POLICY  
  2. #   ifdef _SIGSLOT_SINGLE_THREADED  
  3. #       define SIGSLOT_DEFAULT_MT_POLICY single_threaded  
  4. #   else  
  5. #       define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local  
  6. #   endif  
  7. #endif  

        has_slots类则维护了一个signal对象集合,支持has_slots对象复制操作,此时会将连接中的对像替换成新的对象。除此之外还支持连接和断开连接操作。其它的类,参见图中的描述。

  • 完整的Signal示例
        上面提到的Signal的用法,实际上是摘自libjingle文档。下面是基于此的一个完整的可运行的示例,此处只用到了sigslot库,sigslot库实际上就只有一个头文件sigslot.h。

[html]  view plain copy
  1. #include <ctime>  
  2. #include <iostream>  
  3. #include <string>  
  4. #include "talk/base/sigslot.h"  
  5.   
  6. class Sender  {  
  7. public:  
  8.   sigslot::signal2<std::string, std::time_t> SignalDanger;  
  9.   
  10.   void Panic(){  
  11.     SignalDanger("Help!", std::time(0));  
  12.   }  
  13. };  
  14.   
  15. class Receiver : public sigslot::has_slots<> {  
  16. public:  
  17.   Receiver(Sender& sender){  
  18.     sender.SignalDanger.connect(this, &Receiver::OnDanger);  
  19.   }  
  20.   
  21.   void OnDanger(std::string message, std::time_t time){  
  22.     if(message == "Help!")  
  23.     {  
  24.       std::cout << "Call the police" << std::endl;  
  25.     }  
  26.   }  
  27. };  
  28.   
  29. int main(int argc, char** argv)  
  30. {  
  31.   Sender sender;  
  32.   Receiver receiver(sender);  
  33.   sender.Panic();  
  34.   return 0;  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值