sigslot库源码分析
言歸正傳,sigslot是一個(gè)用標(biāo)準(zhǔn)C++語法實(shí)現(xiàn)的信號(hào)與槽機(jī)制的函數(shù)庫,類型和線程安全。提到信號(hào)與槽機(jī)制,恐怕最容易想到的就是大名鼎鼎的Qt所支持的對(duì)象之間通信的模式吧。不過這里的信號(hào)與槽雖然在概念上等價(jià)與Qt所實(shí)現(xiàn)的信號(hào)與槽,但是采用的僅僅是標(biāo)準(zhǔn)C++語法,不像Qt采用了擴(kuò)展C++語言的方式(Qt需要使用moc工具對(duì)代碼預(yù)處理之后,才能由標(biāo)準(zhǔn)的C++編譯器進(jìn)行編譯)。
眾所周知,C++是一門特性眾多的語言,其支持多種編程范式。雖然C++在一定程度上支持OOP編程,但是C++這種“靜態(tài)消息機(jī)制”的語言一直沒有實(shí)現(xiàn)對(duì)象級(jí)別的delegate機(jī)制,而C++之父Bjarne主張的“庫擴(kuò)展勝于語言擴(kuò)展”的做法使得各種解決方案層出不窮。除了信號(hào)與槽機(jī)制,C++11正式加入的std:bind/std::function組合也提供了優(yōu)秀的解決方案。這里所說的信號(hào)與槽機(jī)制也是一種對(duì)象間通信的機(jī)制,具體的討論也可以看看sigslot相關(guān)介紹中的內(nèi)容。
sigslot主頁:?http://sigslot.sourceforge.net
sigslot文檔:?http://sigslot.sourceforge.net/sigslot.pdf
sigslot?庫的用法文檔中已然很明了了,所以在這里就不贅述了。接下來我們看看這個(gè)庫的實(shí)現(xiàn)。源碼分析的方法有很多種,具體到庫代碼的分析的方法,我喜歡的是先研究庫的功能,直到能寫出一個(gè)demo程序?yàn)橹埂Q芯恳粋€(gè)庫的前提是你得會(huì)用它,熟悉它的接口。讀完文檔,很容易就寫出了下面的測(cè)試代碼:
using namespace sigslot;class Switch { public:signal0<> clicked; };class Light : public has_slots<> { public:void turn_on(){std::cout << "Turn on ~" << std::endl;}};int main(int argc, char *argv[]) {Light lit1;Switch swh;swh.clicked.connect(&lit1, &Light::turn_on);swh.clicked.emit();return 0; }使用方法很簡(jiǎn)單。從這里我們就能看出來,這個(gè)庫無非就是在信號(hào)那一端保存了這個(gè)信號(hào)所綁定的函數(shù)指針,在槽函數(shù)這一端保存了其綁定的信號(hào)而已。接下來的問題實(shí)際上就是采用合理的數(shù)據(jù)結(jié)構(gòu)來處理問題了。
sigslot庫簡(jiǎn)單到只有一個(gè)頭文件?sigslot.h?,打開后洋洋灑灑幾千行代碼,其實(shí)仔細(xì)看看絕大多數(shù)代碼都是為了適應(yīng)參數(shù)數(shù)量不同的成員函數(shù)指針的定義,為其擴(kuò)展的模版代碼。從定義上看,這個(gè)庫支持?0~8?個(gè)參數(shù)的成員函數(shù)綁定。在紙上畫一下類的繼承關(guān)系,很容易就得到了如下的函數(shù)繼承圖(?IDE?有相關(guān)的工具也可以拿來用?~?)?:
從這個(gè)圖上看,其實(shí)代碼關(guān)系已經(jīng)很清晰了。?實(shí)現(xiàn)了槽函數(shù)的類需要繼承?has_slots?類。而?has_slots類?擁有一個(gè)?std::set<_signal_base<mt_policy>*>?類型的容器(所有的?mt_policy?其實(shí)是庫定義的三種鎖策略而已[單線程無鎖、多線程共享全局鎖、多線程局部鎖])。所有的?_signal_base[0-8]?的類持有各自的?std::list<_connection_base[0-8]<mt_policy?>?>?的list容器,而?_connection_base[0-8]?則分別封裝了0~8個(gè)參數(shù)的成員函數(shù)的指針。
這里的重復(fù)代碼是很多的,作為分析的話完全可以每中類代碼只留下一個(gè),這樣所有的代碼就精簡(jiǎn)到只有6個(gè)類了(反正別的也只是為了適應(yīng)參數(shù)個(gè)數(shù)寫的模版罷了,代碼除了參數(shù)個(gè)數(shù)外都是一樣的)。
至于前面說到的鎖,其實(shí)也只是因?yàn)镃++ STL庫中的容器本身不是線程安全的,需要在外部加鎖。鎖的實(shí)現(xiàn)很平常,另外用C++ RAII手法封裝的lock_block類也是常見的用法。唯一需要注意的是,這個(gè)庫在使用了信號(hào)與槽的用戶類發(fā)生了拷貝構(gòu)造時(shí),其信號(hào)與槽的綁定關(guān)系也會(huì)被拷貝,所以代碼中的類都自行編寫了相關(guān)的拷貝構(gòu)造函數(shù)。這里稍微解釋下,如果A類的a對(duì)象的x信號(hào)和B類的b1對(duì)象的y函數(shù)綁定,然后用b1初始化構(gòu)造b2(即 B b2(b1))。這時(shí)候,A類的a對(duì)象的x信號(hào)也會(huì)綁定到b2對(duì)象的y函數(shù)。這個(gè)特性我感覺有點(diǎn)莫名其妙,而且使得代碼復(fù)雜了不少(我覺得沒必要這么設(shè)計(jì),用戶需要這個(gè)特性的話,自己再調(diào)用一次綁定函數(shù)就是了)。
知曉了基本的原理之后,看代碼就很容易了。比如在擁有信號(hào)和擁有槽函數(shù)的對(duì)象析構(gòu)時(shí),會(huì)自動(dòng)的取消掉之前的綁定,代碼很清晰易讀的。下面是我自己根據(jù)sigslot的原理,簡(jiǎn)化出來的代碼,大家可以先看看然后去讀sigslot的源碼會(huì)簡(jiǎn)單很多。
總結(jié)
以上是生活随笔為你收集整理的sigslot库源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win10下VS2015(WDK10)驱
- 下一篇: Linux-(C/C++)动态链接库生成