概述
- 摘要
本文主要分析了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函数中。
// 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的实现。
#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示例
#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源码分析之一:Signal机制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复