觀察者模式的應用,主要的行為就是注冊和移除觀察者(observer),以及通知所有已注冊的Observers。這裡介紹的是Chromium項目中實作的線程安全的觀察者管理及通知的基礎類ObserverListThreadSafe, 它的能力包括:
觀察者可以在任意線程中注冊,消息回調會發生在注冊時所在的線程。
任意線程可以Notify()觸發通知消息。
觀察者可以在回調時從清單中移除自己。
如果一個線程正在通知觀察者, 此時一個觀察者正在從清單中移除自己, 通知會被丢棄。
實作這個基礎是記錄線程與觀察者清單的對應關系,即某個線程上存在的觀察者的清單。定義如下:
其中PlatformThreadID為線程的ID, 而ObserverListContext是一個數組,其定義如下:
其中loop為Chromium線程機制中的MessageLoopProxy, 也可以了解為線程的消息隊列代理,使用它就可以完成将某個操作抛到指定線程上運作。list就很好了解了,記錄的是該線程中的觀察者清單。
隻要全局的持有這個表(ObserversListMap),就可以将觀察者與線程關聯起來,進而保證通知一定可以運作到它注冊時所在的線程。

其中ObserverListThreadSafe就是我們的主角。它本身是為一個模闆類:
下面是一個使用的示例:
添加/删除Observer方法很簡單:
當需要通知各個觀察者時,代碼如下:
即内部成員變量list_lock_,在操作observer_list_要使用如下方法加鎖:
基本思路就是:
* 以目前線程ID,找到ObserverListContext。如果新增但又沒有,則建立。
* 操作找到的ObserverListContext進行添加或删除操作。
下面是AddObserver()的實作:
這個過程實作上,因為需要相容不同數理的參數,是以定義了一組模闆方法。先說明一下基本思路:
* 封裝要調用的通知方法為Callback形式:函數,及使用tuple(不是C++11的元組,而是base::tuple)封裝起來的參數。
* 周遊observer_lists_,找到每個線程對應的ObserverListContext。
* 使用ObserverListContext中記錄的MessageProxyLoop,執行NotifyWrapper,并傳入Callback作為參數。
以上這個過程就是在通知的線程的完成的, 具體的代碼如下:
下一步就是在各個observer所在的線程上觸發NotifyWrapper了。它主要做兩件事:
* 為每一個observer運作通知的函數:
如果發現這個線程上已經沒有可用的觀察者,則将它從observer_list_中移除。
再回頭看一下對回調方法封裝,上面提到了參數是使用base::tuple封裝的,它同時也提供了DispatchToMethod方法,把參數解開,再調用方法,詳見base::tuple中的說明。
下面是UnboundMethod的定義:
如果沒有Chromium的線程機制,也是可以實作的,核心是線程的抛轉。
這種方法适用于多線程下以函數+參數通知的方式。參數直接抛轉到指定的線程不用特别擔心線程安全問題。對于獲得通知後仍然要跨線程通路資料的情況,則可以考慮: 1.以類似的方式,将資料通過函數參數傳遞(目前最多為6個)。 2. 如果資料量大,則可以考慮使用Multiversion Concurrency Control的算法,盡量避免加鎖的開銷。