寫在轉載之前的:
webrtc的源碼中用到了sigslot機制,可以看看webrtc/examples/peerconnection/client/中的peer_connection_client.cc和peer_connection_client.h代碼裏是怎麼用的。sigslot.h原先位於webrtc/base/下,最新的代碼挪到了webrtc/rtc_base/third_party/sigslot/下。依葫蘆畫瓢,就能夠學會怎麼去使用它,至少看到別人的代碼裏有用到它的地方也能夠理解。
以下轉載內容:
Sigslot 是Sarah Thompson 設計實現的C++ 事件處理的框架, 這套框架非常輕量級, 全部代碼只有一個sigslot.h 文件, 其設計也非常出色, 最大限度的將事件和處理機制解耦, 並且保證了線程安全.
在WebRTC中, sigslot 是其基礎的事件處理框架, 在多個模塊的消息通知, 響應處理中被使用. 下文, 我們簡單的來剖析下sigslot 的原理及其應用.
在C++中, 普通的事件處理也容易實現, 下面是一個簡單的例子, 描述電燈開關工作:
class Switch
{
public:
virtual void Clicked() = 0;
};
class Light
{
public:
void Toggle();
};
class ToggleSwitch : public Switch
{
public:
ToggleSwitch(Light & light) {
m_light = light;
}
virtual void Clicked() {
m_light.Toggle();
}
private:
Light & m_light;
};
// how to toggle light
Light red, white;
ToggleSwitch sw1(red), sw2(white);
sw1.Clicked();
sw2.Clicked();
上面的代碼可以工作的很好, 但是有一個弊端是: ToggleSwitch 必須得到Light的引用, 然後去顯式調用Light的Toggle函數, 這樣的話, Swich 和 Light 之間是緊耦合. 如果我希望未來Switch 可以去控制某個馬達(Motor), 將不得不修改代碼.
有一個改進的方案是利用C++的多態, 比如設計一個虛接口: SwithableItem, 讓Motor 和 Light 繼承自這個虛接口. 這也是不錯的思路. 不過在這裏sigslot 利用C++ template, 提供了一種更加優雅的方式, 還是繼續來看代碼:
class Switch
{
public:
sigslot::signal0<> Clicked;
};
class Light : public sigslot::has_slot<>
{
public:
void Toggle();
};
Switch sw1, sw2;
Light red, white;
sw1.Clicked.connect(&red, &Light::Toggle);
sw2.Clicked.connect(&white, &Light::Toggle);
sw1.Clicked();
sw2.Clicked();
這段代碼的功能跟上面的完全一樣,但是最大的區別在於:Switch跟Light之間的綁定關係是在運行期建立的, 跟Swtich 和 Light 本身的設計無關! 這真是令人驚歎的設計!
關於sigslot的好處,我想已經不必多言. 讀者可以去sigslot的主頁上下載代碼,試着在你的工程中用一下sigslot,仔細閱讀理解下其源碼,你一定會有所收穫!
下面貼一下webrtc中關於sigslot使用的代碼片斷:
class VideoCapturer : public sigslot::has_slots<>,
public rtc::VideoSourceInterface<cricket::VideoFrame> {
......
sigslot::signal2<VideoCapturer*, const CapturedFrame*,
sigslot::multi_threaded_local> SignalFrameCaptured;
};
void VideoCapturer::Construct() {
enable_camera_list_ = false;
capture_state_ = CS_STOPPED;
SignalFrameCaptured.connect(this, &VideoCapturer::OnFrameCaptured);
scaled_width_ = 0;
scaled_height_ = 0;
enable_video_adapter_ = true;
// There are lots of video capturers out there that don't call
// set_frame_factory. We can either go change all of them, or we
// can set this default.
// TODO(pthatcher): Remove this hack and require the frame factory
// to be passed in the constructor.
set_frame_factory(new WebRtcVideoFrameFactory());
}
void SignalCapturedFrame(cricket::CapturedFrame* frame) {
SignalFrameCaptured(this, frame);
}
Reference:
1 Sigslot 項目主頁: http://sigslot.sourceforge.net/