boost------signals2的使用1(Boost程序库完全开发指南)读书笔记
signals2基于Boost的另一個(gè)庫(kù)signals,實(shí)現(xiàn)了線程安全的觀察者模式。在signals2庫(kù)中,觀察者模式被稱為信號(hào)/插槽(signals and slots),他是一種函數(shù)回調(diào)機(jī)制,一個(gè)信號(hào)關(guān)聯(lián)了多個(gè)插槽,當(dāng)信號(hào)發(fā)出時(shí),所有關(guān)聯(lián)它的插槽都會(huì)被調(diào)用。
許多成熟的軟件系統(tǒng)都用到了這種信號(hào)/插槽機(jī)制(另一個(gè)常用的名稱是事件處理機(jī)制:event/event handler),它可以很好地解耦一組互相協(xié)作的類,有的語(yǔ)言設(shè)置直接內(nèi)建了對(duì)它的支持(如c#),signals2以庫(kù)的形式為c++增加了這個(gè)重要的功能。
?
1、操作函數(shù)
signal最重要的操作函數(shù)是插槽管理connect()函數(shù),它吧插槽連接到信號(hào)上,相當(dāng)于為信號(hào)(事件)增加了一個(gè)處理的handler。
插槽可以是任意的可調(diào)用對(duì)象,包括函數(shù)指針、函數(shù)對(duì)象、以及它們的bind表達(dá)式和function對(duì)象,signal內(nèi)部使用function作為容器來(lái)保存這些可調(diào)用對(duì)象。連接時(shí)可以指定組號(hào)也可以不指定組號(hào),當(dāng)信號(hào)發(fā)生時(shí)將依據(jù)組號(hào)的排序準(zhǔn)則依次調(diào)用插槽函數(shù)。
如果連接成功connect()將返回一個(gè)connection,表示了信號(hào)與插槽之間的連接關(guān)系,它是一個(gè)輕量級(jí)的對(duì)象,可以處理兩者間的連接,如斷開(kāi)、重連接、或者測(cè)試連接狀態(tài)。
成員函數(shù)disconnect()可以斷開(kāi)插槽與信號(hào)的連接,它有兩種形式:傳遞組號(hào)將斷開(kāi)該組的所有插槽,傳遞一個(gè)插槽對(duì)象將僅斷開(kāi)該插槽。函數(shù)disconnect_all_slots()可以一次性斷開(kāi)信號(hào)的所有插槽連接。
?
2、插槽的連接于使用
signal就像一個(gè)增強(qiáng)的function對(duì)象,它可以容納(使用connect())多個(gè)符合模板參數(shù)中函數(shù)簽名類型的函數(shù)(插槽),形成一個(gè)插槽鏈表,然后在信號(hào)發(fā)生時(shí)一起調(diào)用:
?
#include "stdafx.h" #include "boost/utility/result_of.hpp" #include "boost/typeof/typeof.hpp" #include "boost/assign.hpp" #include "boost/ref.hpp" #include "boost/bind.hpp" #include "boost/function.hpp" #include "boost/signals2.hpp" #include "iostream" using namespace std;void slots1() {cout << "slots1 call" << endl; }void slots2() {cout << "slots2 call" << endl; }struct Hello {void operator()() const {std::cout << "Hello";} };int _tmain(int argc, _TCHAR* argv[]) {boost::signals2::signal<void()> sig;sig.connect(&slots1);sig.connect(&slots2);sig();boost::signals2::signal<void ()> sig1;sig1.connect(Hello());sig1();return 0; }?
?
注:編譯這個(gè)程序的時(shí)候,確保已經(jīng)在stdafx.h中加入#define _SCL_SECURE_NO_WARNINGS或者,在C/C++----預(yù)處理器----預(yù)處理器定義中加上了_SCL_SECURE_NO_WARNINGS,否則會(huì)引發(fā)錯(cuò)誤(或不能正確輸出),下同。
在連接插槽時(shí)省了了connect()的第二個(gè)參數(shù)connect_position,它的缺省值是at_back,表示插槽將插入到信號(hào)插槽鏈表的尾部,因此slot2將在slot1之后被調(diào)用。
下面是使用和組號(hào)的情況:
#include "stdafx.h" #include "boost/utility/result_of.hpp" #include "boost/typeof/typeof.hpp" #include "boost/assign.hpp" #include "boost/ref.hpp" #include "boost/bind.hpp" #include "boost/function.hpp" #include "boost/signals2.hpp" #include "iostream" using namespace std;template<int N> struct Slot {void operator()(){cout << "Slot current N value is : " << N << endl;} };int _tmain(int argc, _TCHAR* argv[]) {boost::signals2::signal<void()> sig;sig.connect(Slot<1>(), boost::signals2::at_back); // 最后一個(gè)被調(diào)用sig.connect(Slot<99>(), boost::signals2::at_front); // 第一個(gè)被調(diào)用sig.connect(5, Slot<55>(), boost::signals2::at_back); // 組號(hào)5的最后一個(gè)sig.connect(5, Slot<57>(), boost::signals2::at_front);// 組號(hào)5的第一個(gè)sig.connect(10, Slot<100>());// 組號(hào)10該組只有一個(gè)sig();return 0; }?
3、信號(hào)的返回值
signal如function一樣,不僅可以把輸入?yún)?shù)轉(zhuǎn)發(fā)給所以插槽,也可以傳回插槽的返回值。默認(rèn)情況下signal使用合并器optional_last_value<R>,它將使用optional對(duì)象返回最后被調(diào)用的插槽的返回值。
#include "stdafx.h" #include "boost/utility/result_of.hpp" #include "boost/typeof/typeof.hpp" #include "boost/assign.hpp" #include "boost/ref.hpp" #include "boost/bind.hpp" #include "boost/function.hpp" #include "boost/signals2.hpp" #include "iostream" using namespace std;template<int N> struct Slot {int operator()(int x){cout << "Slot current N * x value is : " << endl;return (N * x);} };int _tmain(int argc, _TCHAR* argv[]) {boost::signals2::signal<int(int)> sig;sig.connect(Slot<10>());sig.connect(Slot<100>());cout << *sig(2) << endl;;return 0; }?
signal的operator()調(diào)用這時(shí)需要傳入一個(gè)整數(shù)參數(shù),這個(gè)參數(shù)會(huì)被signal存儲(chǔ)一個(gè)拷貝,然后轉(zhuǎn)發(fā)給各個(gè)插槽。最后signal將返回插槽鏈表末尾slots<100>()的計(jì)算結(jié)果,它是一個(gè)optional對(duì)象,必須用接引用操作符*來(lái)獲得值(但你可以發(fā)現(xiàn)Slotcurrent N * x value is是輸出了兩次的)。
?
4、合并器
?
大多數(shù)時(shí)候,插槽的返回值都是有意義的,需要以某種方式處理多個(gè)插槽的返回值。
signal允許用戶自定義合并器來(lái)處理插槽的返回值,把多個(gè)插槽的返回值合并為一個(gè)結(jié)果返回給用戶。
#include "stdafx.h" #include "boost/utility/result_of.hpp" #include "boost/typeof/typeof.hpp" #include "boost/assign.hpp" #include "boost/ref.hpp" #include "boost/bind.hpp" #include "boost/function.hpp" #include "boost/signals2.hpp" #include "numeric" #include "iostream" using namespace std;template<int N> struct Slot {int operator()(int x){cout << "Slot current N * x value is : " << endl;return (N * x);} };template<typename T> class combiner { public:typedef pair<T, T> result_type;combiner(T t = T()) : v(t){}template<typename InputIterator>result_type operator()(InputIterator begin, InputIterator end) const{if (begin == end){return result_type();}vector<T> vec(begin, end);T sum = accumulate(vec.begin(), vec.end(), v);T max = *max_element(vec.begin(), vec.end());return result_type(sum, max);}private:T v; };int _tmain(int argc, _TCHAR* argv[]) {boost::signals2::signal<int(int), combiner<int> > sig;sig.connect(Slot<10>());sig.connect(Slot<20>());sig.connect(Slot<3>());BOOST_AUTO(x, sig(2));cout << x.first << ", " << x.second << endl;return 0; }?
combiner類的調(diào)用操作符operator()的返回值類型可以是任意類型,完全由用戶指定,不一定必須是optional或者是插槽的返回值類型。operator()的模板參數(shù)InputIterator是插槽鏈表的返回值迭代器,可以使用它來(lái)遍歷所有插槽的返回值,進(jìn)行所需的處理。
當(dāng)信號(hào)被調(diào)用時(shí),signal會(huì)自動(dòng)把引用操作轉(zhuǎn)換為插槽調(diào)用,將調(diào)用給定的合并器的operator()逐個(gè)處理插槽的返回值,并最終返回合并器operator()的結(jié)果。
如果我們不適用signal的缺省構(gòu)造函數(shù),而是在構(gòu)造signal時(shí)傳入一個(gè)合并器的實(shí)例,那么signal將使用逐個(gè)合并器(的拷貝)處理返回值。例如,下面的代碼使用了一個(gè)有初值的合并器對(duì)象,累加值從100開(kāi)始:
signal<int(int),combiner<int> > sig(combiner<int>(100));
?
?
5、管理信號(hào)的連接
?
信號(hào)與插槽的鏈接并不要求是永久的,當(dāng)信號(hào)調(diào)用玩插槽后,有可能需要把插槽從信號(hào)中斷開(kāi),再連接到其他的信號(hào)上去。
signal可以用成員函數(shù)disconnect()斷開(kāi)一個(gè)或一組插槽,或者使用disconnect_all_slots()斷開(kāi)所有插槽連接,函數(shù)empty()和num_slots()用來(lái)檢測(cè)信號(hào)當(dāng)前插槽的連接狀態(tài)。
要斷開(kāi)一個(gè)插槽,插槽必須能夠進(jìn)行登記等價(jià)比較,對(duì)于函數(shù)對(duì)象來(lái)說(shuō)就是重載一個(gè)等價(jià)語(yǔ)義的operator==。下面對(duì)slots<N>增加一個(gè)等價(jià)比較:
#include "stdafx.h" #include "boost/utility/result_of.hpp" #include "boost/typeof/typeof.hpp" #include "boost/assign.hpp" #include "boost/ref.hpp" #include "boost/bind.hpp" #include "boost/function.hpp" #include "boost/signals2.hpp" #include "numeric" #include "iostream" using namespace std;template<int N> struct Slot {int operator()(int x){cout << "Slot current N * x value is : " << endl;return (N * x);} };template<int N> bool operator== (const Slot<N>& a, const Slot<N>& b) {return true; }template<typename T> class combiner { public:typedef pair<T, T> result_type;combiner(T t = T()) : v(t){}template<typename InputIterator>result_type operator()(InputIterator begin, InputIterator end) const{if (begin == end){return result_type();}vector<T> vec(begin, end);T sum = accumulate(vec.begin(), vec.end(), v);T max = *max_element(vec.begin(), vec.end());return result_type(sum, max);}private:T v; };int _tmain(int argc, _TCHAR* argv[]) {boost::signals2::signal<int(int)> sig;// assert(sig.empty());sig.connect(0, Slot<10>());sig.connect(Slot<20>());sig.connect(1, Slot<30>());assert(sig.num_slots() == 3);sig.disconnect(0);// assert(sig.num_slots() == 1);sig.disconnect(Slot<30>());// assert(sig.empty());sig(2);return 0; }?
6、更靈活的管理信號(hào)連接
signals2庫(kù)提供另外一種較為靈活的連接管理方式:使用connection對(duì)象。
每當(dāng)signal使用connect()連接插槽時(shí),他就會(huì)返回一個(gè)connection對(duì)象。connection對(duì)象像是信號(hào)與插槽連接關(guān)系的一個(gè)句柄(handle),可以管理鏈接:
#include "stdafx.h" #include "boost/utility/result_of.hpp" #include "boost/typeof/typeof.hpp" #include "boost/assign.hpp" #include "boost/ref.hpp" #include "boost/bind.hpp" #include "boost/function.hpp" #include "boost/signals2.hpp" #include "numeric" #include "iostream" using namespace std;template<int N> struct Slot {int operator()(int x){cout << "Slot current N * x value is : " << endl;return (N * x);} };template<int N> bool operator== (const Slot<N>& a, const Slot<N>& b) {return true; }template<typename T> class combiner { public:typedef pair<T, T> result_type;combiner(T t = T()) : v(t){}template<typename InputIterator>result_type operator()(InputIterator begin, InputIterator end) const{if (begin == end){return result_type();}vector<T> vec(begin, end);T sum = accumulate(vec.begin(), vec.end(), v);T max = *max_element(vec.begin(), vec.end());return result_type(sum, max);}private:T v; };int _tmain(int argc, _TCHAR* argv[]) {boost::signals2::signal<int(int)> sig;boost::signals2::connection c1 = sig.connect(0, Slot<10>());boost::signals2::connection c2 = sig.connect(0, Slot<10>());boost::signals2::connection c3 = sig.connect(0, Slot<10>());c1.disconnect();assert(sig.num_slots() == 2);assert(!c1.connected());assert(c2.connected());return 0; }另外一種連接管理對(duì)象是scoped_connection,它是connection的種類,提供類似scoped_ptr的RAII功能:插槽與信號(hào)的連接僅在作用域內(nèi)生效,當(dāng)離開(kāi)作用域時(shí)連接就會(huì)自動(dòng)斷開(kāi)。當(dāng)需要臨時(shí)連接信號(hào)時(shí)scoped_connection會(huì)非常有用:
#include "stdafx.h" #include "boost/utility/result_of.hpp" #include "boost/typeof/typeof.hpp" #include "boost/assign.hpp" #include "boost/ref.hpp" #include "boost/bind.hpp" #include "boost/function.hpp" #include "boost/signals2.hpp" #include "numeric" #include "iostream" using namespace std;template<int N> struct Slot {int operator()(int x){cout << "Slot current N * x value is : " << endl;return (N * x);} };template<int N> bool operator== (const Slot<N>& a, const Slot<N>& b) {return true; }template<typename T> class combiner { public:typedef pair<T, T> result_type;combiner(T t = T()) : v(t){}template<typename InputIterator>result_type operator()(InputIterator begin, InputIterator end) const{if (begin == end){return result_type();}vector<T> vec(begin, end);T sum = accumulate(vec.begin(), vec.end(), v);T max = *max_element(vec.begin(), vec.end());return result_type(sum, max);}private:T v; };int _tmain(int argc, _TCHAR* argv[]) {boost::signals2::signal<int(int)> sig;sig.connect(0, Slot<10>());assert(sig.num_slots() == 1);{boost::signals2::scoped_connection sc = sig.connect(0, Slot<20>());assert(sig.num_slots() == 2);}assert(sig.num_slots() == 1);return 0; }?
插槽與信號(hào)的連接一旦斷開(kāi)就不能再連接起來(lái),connection不提供reconnet()這樣的函數(shù)。但可以暫時(shí)地阻塞插槽與信號(hào)的連接,當(dāng)信號(hào)發(fā)生時(shí)被阻塞的插槽將不會(huì)被調(diào)用,connection對(duì)象的blocked()函數(shù)可以檢查插槽是否被阻塞。但被阻塞的插槽并沒(méi)有斷開(kāi)與信號(hào)的鏈接,在需要的時(shí)候可以隨時(shí)解除阻塞。
connection對(duì)象自身沒(méi)有阻塞的功能,他需要一個(gè)輔助類shared_connection_block,它將阻塞connection對(duì)象,知道它被析構(gòu)或者顯式調(diào)用unblock()函數(shù):
?
#include "stdafx.h" #include "boost/utility/result_of.hpp" #include "boost/typeof/typeof.hpp" #include "boost/assign.hpp" #include "boost/ref.hpp" #include "boost/bind.hpp" #include "boost/function.hpp" #include "boost/signals2.hpp" #include "numeric" #include "iostream" using namespace std;template<int N> struct Slot {void operator()(int x){cout << "Slot current N is : " << N << endl;} };template<int N> bool operator== (const Slot<N>& a, const Slot<N>& b) {return true; }template<typename T> class combiner { public:typedef pair<T, T> result_type;combiner(T t = T()) : v(t){}template<typename InputIterator>result_type operator()(InputIterator begin, InputIterator end) const{if (begin == end){return result_type();}vector<T> vec(begin, end);T sum = accumulate(vec.begin(), vec.end(), v);T max = *max_element(vec.begin(), vec.end());return result_type(sum, max);}private:T v; };int _tmain(int argc, _TCHAR* argv[]) {boost::signals2::signal<void(int)> sig;boost::signals2::connection c1 = sig.connect(0, Slot<10>());boost::signals2::connection c2 = sig.connect(0, Slot<20>());assert(sig.num_slots() == 2);sig(2);cout << "begin blocking..." << endl;{boost::signals2::shared_connection_block block(c1);assert(sig.num_slots() == 2);assert(c1.blocked());sig(2);}cout << "end blocking.." << endl;assert(!c1.blocked());sig(2);return 0; }?
轉(zhuǎn)載于:https://www.cnblogs.com/jiangu66/p/3230969.html
總結(jié)
以上是生活随笔為你收集整理的boost------signals2的使用1(Boost程序库完全开发指南)读书笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: .NET下安装卸载WindowsServ
- 下一篇: 新站收录记录