Unix/C++--信号与槽机制的理解
1 简介
- 信号槽是观察者模式的一种实现,或者说是一种升华。
- 一个信号就是一个能够被观察的事件,或者至少是事件已经发生的一种通知;一个槽就是一个观察者,通常就是在被观察的对象发生改变的时候——也可以说是信号发出的时候——被调用的函数;信号和槽是多对多的关系。一个信号可以连接多个槽,而一个槽也可以监听多个信号。信号可以有附加信息。
- 信号槽这一术语最初来自 Trolltech 公司的 Qt 库(现在已经被 Nokia 收购)。1994年,Qt 的第一个版本发布,为我们带来了信号槽的概念。这一概念立刻引起计算机科学界的注意,提出了多种不同的实现。如今,信号槽依然是 Qt 库的核心之一,其他许多库也提供了类似的实现,甚至出现了一些专门提供这一机制的工具库。
2 机制
3 与回调对比
回调紧耦合,非类型安全,
信号与槽松耦合,类型安全。
4 Qt 信号与槽
4.1 优点
- 松耦合
- 类型安全
- 灵活
- 使用简单方便
4.2 缺点
- 速度不及回调函数 (根据网上测试数据来看在5-10倍,us级别)
博主朝闻道:Qt 的信号与槽机制介绍(10个要注意的问题)
速度上低于回调函数,在一台 i586-133 的机器上测试是 10 微秒(运行 Linux),[linux内核调用在低精度下在ms级别。] 如果我们要追求高效率的话,比如在实时系统中就要尽可能的少用这种机制。
博主甲:QT 信号与槽效率测试
在release模式下,信号槽打印平均0.5微秒,函数直接调用0.1微秒,
两者结合应该可以肯定信号槽会比函数直接调用方式慢,大概会慢5倍
4.3 注意
- 调用不当出现死循环
在定义槽函数时一定要注意避免间接形成无限循环,即在槽中再次发射所接收到的同样信号。 - 槽函数执行顺序随机
如果一个信号与多个槽相联系的话,那么,当这个信号被发射时,与之相关的槽被激活的顺序将是随机的。 - 宏定义不能用在 signal 和 slot 的参数中
- 构造函数不能用在 signals 或者 slots 声明区域内。
- 函数指针不能作为信号或槽的参数。
- 信号与槽不能有默认参数
- 信号与槽也不能携带模板类参数,可以使用 typedef 语句来绕过这个限制
- 嵌套的类不能位于信号或槽区域内,也不能有信号或者槽。
- 友元声明不能位于信号或者槽声明区内。
5 库对比
- 信号槽系统常用的有三种:boost的signals,sigslot,sigc++
基本功能有:connect、disconnect、emit - sigslot优缺点
优点
1.不用担心空回调,当回调对象析构时会自动disconnect
2.支持多线程,线程安全,有锁
缺点
1.只能回调void类型函数,不支持返回值。boost中的signals库架构类似,支持返回值,但引入了boost中的其他库
2.slot没有优先级,不能动态调整回调队列中的先后顺序
注:
slot函数(被回调的函数)就是普通的成员函数,但有以下限制:
1.返回值必须为void
2.Slot参数个数范围为0-8个
3.实现slot的类必须继承自has_slots<> 1,2是sigslot库作者的限制,作者权衡各方面因素后做出的决定,如果你觉得有必要你可以修改sigslot代码取消该限制,而3是sigslot的机制基础,必须遵守,除非你自己重新写个sigslot - from 朝闻道
C++的其它signal-slot实现(10来个) good
- pbhogan/Signals介绍中,强调比libsigc ++,sigslot和boost.signals更简单,更高效。但是14年后没有维护过,暂且不去研究。
- libsigc ++: gtkmm使用libsigc ++来包装GTK +信号系统。 它不依赖于GTK +或gtkmm。(GTK能用,说明linux使用完全没问题)
6 libsigc ++使用
- libsigc++是一个callback的完整包装,Bjarne Stroustrup都对libsigc++大为推荐。
- 从github连接 下载
- 选择分支,博主选17v3
- ubuntu中解压
cd libsigcpp
mkdir release
cd release
cmake -D CMAKE_BUILD_TYPE=RELEASE -DCMAKE_INSTALL_PREFIX=/home/myname/Desktop/local ..
make
make install
then success
貌似头文件太多了,库也多。先用着,后面封装自己的,尽量轻量化。
链接libsigc++AddRelease
使用:
信号槽库:sigslot.h和sigc++使用
libsigc++库的使用
介绍一个类型安全的回调库:libsigc++
libsigc+±1.2.5库的使用
7 使用注意事项
信号和槽的绑定connect在构造函数中执行,如果放在别的地方可能一次emit sig,slot函数多次执行
8 示例
8.1 类内slot connect 别的类sig
sigc::connection ccSg1 = sg1.connect(sigc::ptr_fun(&func1));
class mySlot: public : sigc::trackable
{
public:
int func2(char*, double)(){}
} obj;
sigc::connection ccSg2 = sg2.connect(sigc::mem_fun2(obj,&mySlot::func));
class mySg: public : sigc::trackable
{
mySg(){auto ccIter_Sg3 = sg3.connect(sigc::mem_fun(*this,&mySg::on_func));}
sigc::signal2<int, char*, double> sg3;
int on_func(char*, double)(){}
}
参考
1、signal-slot 信号/槽(也译信号/插槽)机制
2、QT 信号与槽
3、C++的其它signal-slot实现(10来个) good
4、sigslot(c++信号槽库)源码分析
5、sigslot - C++ Signal/Slot Library
6、libsigcplusplus–github
7、pbhogan/Signals
8、c++超级好用的回调signal slot
9、Qt 之 信号槽机制及优缺点
10、Qt 信号和槽机制 优点 效率的详解
11、Qt 的信号与槽机制介绍(10个要注意的问题)
12、QT 信号与槽效率测试
13、编译方式参照–ubuntu14.04+cuda8.0(TX2宿主机)安装opencv3.0
14、libsigc++官网
15、深入理解信号槽机制(一)(大局观,讲的不错)
16、good–libsigc++库的使用
17、Sigslot介绍
18、解决如果出现了信号就触发一次,但是却调用多次的情况
19、Boost.Signals vs libsigc++
20、信号槽库:sigslot.h和sigc++使用