我是靠谱客的博主 深情书本,这篇文章主要介绍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函数中。

复制代码
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
// Class that sends the notification. class Sender { // The signal declaration. // The '2' in the name indicates the number of parameters. Parameter types // are declared in the template parameter list. sigslot::signal2<string message, std::time_t time> SignalDanger; // When anyone calls Panic(), we will send the SignalDanger signal. void Panic(){ SignalDanger("Help!", std::time(0)); } // Listening class. It must inherit sigslot. class Receiver : public sigslot::has_slots<>{ // Receiver registers to get SignalDanger signals. // When SignalDanger is sent, it is caught by OnDanger(). // Second parameter gives address of the listener function class definition. // First parameter points to instance of this class to receive notifications. Receiver(Sender sender){ sender->SignalDanger.connect(this, &Receiver.OnDanger); } // When anyone calls Panic(), Receiver::OnDanger gets the message. // Notice that the number and type of parameters match // those in Sender::SignalDanger, and that it doesn't return a value. void OnDanger(string message, std::time_t time){ if(message == "Help!") { // Call the police ... } } ... }

  • 实现

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


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

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


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

复制代码
1
2
3
4
5
6
7
#ifndef SIGSLOT_DEFAULT_MT_POLICY # ifdef _SIGSLOT_SINGLE_THREADED # define SIGSLOT_DEFAULT_MT_POLICY single_threaded # else # define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local # endif #endif

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

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

复制代码
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
#include <ctime> #include <iostream> #include <string> #include "talk/base/sigslot.h" class Sender { public: sigslot::signal2<std::string, std::time_t> SignalDanger; void Panic(){ SignalDanger("Help!", std::time(0)); } }; class Receiver : public sigslot::has_slots<> { public: Receiver(Sender& sender){ sender.SignalDanger.connect(this, &Receiver::OnDanger); } void OnDanger(std::string message, std::time_t time){ if(message == "Help!") { std::cout << "Call the police" << std::endl; } } }; int main(int argc, char** argv) { Sender sender; Receiver receiver(sender); sender.Panic(); return 0; }


最后

以上就是深情书本最近收集整理的关于libjingle源码分析之一:Signal机制的全部内容,更多相关libjingle源码分析之一内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(79)

评论列表共有 0 条评论

立即
投稿
返回
顶部