最近在看webrtc开源代码,最底层封装的消息机制,是基于其has_slots,搜索了一下其资料发现是一个很好用的C++库,先对其简单介绍一下。
插槽机制
插槽系统常用的有三种:boost的signals,sigslot,sigc++
基本功能有:
1.connect
2.disconnect
3.emit
sigslot
sigslot是一个线程安全、类型安全,用C++实现的sig/slot机制(sig/slot机制就是对象之间发送和接收消息的机制)的开源代码库。是一个非常好用的库,只有一个头文件sigslot.h
优点
- 不用担心空回调,当回调对象析构时会自动disconnect
- 支持多线程,线程安全,有锁
缺点
- 只能回调void类型函数,不支持返回值。boost中的signals库架构类似,支持返回值,但引入了boost中的其他库
- slot没有优先级,不能动态调整回调队列中的先后顺序
用法
发送信号
比如ReportError信号,当调用ReportError(“Something went wrong”, ERR_SOMETHING_WRONG);时候,将自动调用ReportError的emit成员函数发出一个信号。发给谁呢?
连接信号
通过调用sig的connect函数建立sig和slot间的对应关系。Connect函数接收两个参数,一个是消息目的对象的地址(指针), 另一个是目的对象的成员函数指针(slot)。为了让整个机制有效运行,目的类必须从has_slots<>继承,并且sig/slot参数 类型必须一致。也可以将一个sig连接到多个slot上,这样每次sig发出信号的时候,每个连接的slot都能收到该信号。
断开信号
通过调用sig的disconnect函数断开sig和slot之间的连接,只有一个参数:目的对象的地址。一般不需要显式调用 disconnect函数,在sig类和目的类(包含slot函数的类)析构函数中将自动调用disconnect断开sig和slot的连接。也可使用 disconnect_all断开该sig的所有slot。
实例
#include "sigslot.h"
using namespace sigslot;
using namespace std;
class Switch
{
public:
signal0<> Clicked;
};
class Light :public has_slots <>
{
public:
Light(bool state)
{
b_state = state;
DisplayState();
}
void ToggleState()
{
b_state = !b_state;
DisplayState();
}
void TurnOn()
{
b_state = TRUE;
DisplayState();
}
void TurnOff()
{
b_state = FALSE;
DisplayState();
}
void DisplayState()
{
printf("The State is %d\n", b_state);
}
private:
bool b_state;
};
int main(int argc, const char* argv[])
{
Switch sw1, sw2, all_on, all_off;
Light lp1(TRUE);
Light lp2(FALSE);
sw1.Clicked.connect(&lp1, &Light::ToggleState);
sw2.Clicked.connect(&lp2, &Light::ToggleState);
all_on.Clicked.connect(&lp1, &Light::TurnOn);
all_on.Clicked.connect(&lp2, &Light::TurnOn);
all_off.Clicked.connect(&lp1, &Light::TurnOff);
all_off.Clicked.connect(&lp2, &Light::TurnOff);
sw1.Clicked();
sw2.Clicked();
all_on.Clicked();
all_off.Clicked();
sw1.Clicked.disconnect(&lp1);
sw2.Clicked.disconnect(&lp2);
all_on.Clicked.disconnect(&lp1);
all_on.Clicked.disconnect(&lp2);
all_off.Clicked.disconnect(&lp1);
all_off.Clicked.disconnect(&lp2);
return 0;
}
备注
从官网上下载下sigslot.h文件之后,引入工程之后会报错误:
Error 2 error C2146: syntax error : missing ‘;’ before identifier ‘const_iterator’ e:\visual studio 2013\test\test\sigslot.h 419 1 Test
修改:
typedef std::set<_signal_base<mt_policy> *> sender_set;
typedef typename sender_set::const_iterator const_iterator;
原因:
因为set本身就是模板,在其模板参数未确定之前,也就是_signal_base 的具体类型没有确定之前,引用其class内部定义的type,这个type也是未知的,加上typename就是告诉编译器先不管具体类型,等模板实例化的时候再确定吧