Chromium base 库中的 Observer 模式实现:ObserverList 与 ObserverListThreadSafe 深度解析
在大型软件系统中,观察者模式(Observer Pattern)是一种非常常用的设计模式,用于对象之间的一对多依赖关系。Chromium 的 base
库提供了 ObserverList
与 ObserverListThreadSafe
两种实现,它们在浏览器内核的事件订阅、异步消息处理、模块解耦中被广泛使用。本文将从概念、源码、用法、对比及常见坑等角度,全面解析 Chromium 中 Observer 模式的实现。
一、Observer 模式概念回顾
Observer 模式,又称发布-订阅模式,核心思想是:
Subject(被观察者):维护一个观察者列表,当自身状态改变时,通知所有观察者。
Observer(观察者):定义一个接口,当被观察者状态发生变化时接收通知。
UML 简单示意:
+-----------+ +------------+ | Subject |<>-------->| Observer | +-----------+ +------------+ | observers | | update() | | attach() | +------------+ | detach() | | notify() | +-----------+
在 Chromium 中,ObserverList
完全实现了这种一对多通知机制,并提供了线程安全版本 ObserverListThreadSafe
。
二、ObserverList 概述
ObserverList
是 Chromium base 提供的非线程安全版本的观察者列表,适用于单线程场景。
1. 头文件及基本类型
#include "base/observer_list.h"
常用类型:
base::ObserverList<MyObserver> observers;
MyObserver
必须是抽象类或接口类。支持三种通知策略:
ObserverListPolicy::EXISTING_ONLY
:只通知已经存在的观察者。ObserverListPolicy::NOTIFY_EXISTING_ONLY
:仅通知当前存在的观察者。ObserverListPolicy::CHECK_EMPTY
:调试模式检查列表为空。
2. ObserverList API
class ObserverList<ObserverType, CheckedType = DEFAULT, AllowEmpty = false> { public: void AddObserver(ObserverType* observer); void RemoveObserver(ObserverType* observer); template <typename Functor> void Notify(Functor functor); // functor 为 observer 的回调函数 };
核心方法
AddObserver/RemoveObserver
添加或移除观察者,必须在同一线程操作。
Notify
遍历观察者列表,并调用回调函数。
内部处理了遍历期间删除 observer 的安全性(使用
ObserverList::ForwardingInfo
)。
3. ObserverList 示例
#include "base/observer_list.h" #include <iostream> class MyObserver { public: virtual void OnEvent(int value) = 0; }; class ConcreteObserver : public MyObserver { public: void OnEvent(int value) override { std::cout << "Received event: " << value << std::endl; } }; int main() { base::ObserverList<MyObserver> observers; ConcreteObserver obs1, obs2; observers.AddObserver(&obs1); observers.AddObserver(&obs2); observers.Notify([](MyObserver* o){ o->OnEvent(42); }); observers.RemoveObserver(&obs1); observers.Notify([](MyObserver* o){ o->OnEvent(100); }); return 0; }
输出结果:
Received event: 42 Received event: 42 Received event: 100
解析
Notify
使用 lambda 遍历ObserverList
,安全处理了 observer 在通知过程中被删除的情况。非线程安全,适用于 UI 或单线程逻辑。
4. ObserverList 内部机制
内部使用 双向链表(
IntrusiveList
)维护 observer。遍历时,使用 ForwardingInfo 记录当前遍历状态,保证删除当前 observer 不会破坏迭代。
CheckedObserverList 可在调试模式下检查空列表或重复添加。
三、ObserverListThreadSafe 概述
ObserverListThreadSafe
是线程安全版本,适用于多线程场景。
1. API
#include "base/observer_list_threadsafe.h" scoped_refptr<base::ObserverListThreadSafe<MyObserver>> observers;
内部使用 引用计数(RefCountedThreadSafe) 管理对象生命周期。
支持在任意线程添加/移除 observer。
通知回调可以指定在哪个线程执行(通过
base::SequencedTaskRunner
)。
2. ObserverListThreadSafe 示例
#include "base/observer_list_threadsafe.h" #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" #include <iostream> class MyObserver { public: virtual void OnEvent(int value) = 0; }; class ConcreteObserver : public MyObserver { public: void OnEvent(int value) override { std::cout << "Thread-safe event: " << value << std::endl; } }; int main() { auto observers = base::MakeRefCounted<base::ObserverListThreadSafe<MyObserver>>(); auto obs = std::make_unique<ConcreteObserver>(); observers->AddObserver(obs.get()); // 在主线程通知 observers->Notify(FROM_HERE, [](MyObserver* o) { o->OnEvent(999); }); return 0; }
特点
Notify
必须传入FROM_HERE
(用于追踪调用栈)和 lambda。支持跨线程安全调用。
内部使用锁或原子操作保证线程安全。
四、ObserverList 与 ObserverListThreadSafe 对比
特性 | ObserverList | ObserverListThreadSafe |
---|---|---|
线程安全 | ❌ 单线程 | ✅ 多线程 |
生命周期管理 | 需外部保证 observer 生命周期 | 内部 ref-count 管理,可延长生命周期 |
通知回调线程 | 当前线程 | 可指定线程 |
性能 | 高(无锁) | 相对低(锁或原子操作) |
使用场景 | UI 线程、单线程任务 | 多线程模块、后台任务 |
五、常见坑与注意事项
1. 遍历中删除 Observer
observers.Notify([&](MyObserver* o){ observers.RemoveObserver(o); // 安全,但注意遍历策略 });
ObserverList
内部已处理遍历中删除安全问题。如果使用
EXISTING_ONLY
策略,可避免通知新加入的 observer。
2. Observer 生命周期管理
对于
ObserverList
,必须确保 observer 生命周期长于列表。对于
ObserverListThreadSafe
,推荐使用scoped_refptr
或WeakPtr
避免悬空调用。
3. 跨线程通知延迟
ObserverListThreadSafe
的通知可能通过任务队列执行,回调不是立即执行。需要注意调用线程与 observer 所在线程。
4. 重复添加与移除
observers.AddObserver(&obs1); observers.AddObserver(&obs1); // 重复添加无效
ObserverList
会检查重复添加。ObserverListThreadSafe
内部同样有重复检查机制。
5. 性能考虑
ObserverListThreadSafe
内部加锁或原子操作,大量高频事件可能有性能开销。对于 UI 更新等高频通知,优先使用单线程
ObserverList
。
六、ObserverList 使用场景分析
1. 单线程 UI 事件
浏览器标签页状态变化
界面组件刷新
Toolbar 按钮点击事件
2. 多线程后台任务
网络模块状态更新
下载任务状态变化
浏览器扩展事件通知
七、实战示例:结合 TaskRunner 异步通知
#include "base/observer_list_threadsafe.h" #include "base/threading/thread_task_runner_handle.h" #include <iostream> class MyObserver { public: virtual void OnDownloadComplete(int id) = 0; }; class DownloadObserver : public MyObserver { public: void OnDownloadComplete(int id) override { std::cout << "Download complete: " << id << std::endl; } }; int main() { auto observers = base::MakeRefCounted<base::ObserverListThreadSafe<MyObserver>>(); DownloadObserver obs; observers->AddObserver(&obs); // 异步任务 base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce([](scoped_refptr<base::ObserverListThreadSafe<MyObserver>> obs){ obs->Notify(FROM_HERE, [](MyObserver* o){ o->OnDownloadComplete(42); }); }, observers)); base::RunLoop().RunUntilIdle(); return 0; }
异步通知保证了 observer 在正确线程执行。
使用
scoped_refptr
管理 ObserverList 生命周期,避免线程结束前被释放。
八、总结
ObserverList
与ObserverListThreadSafe
是 Chromium base 库对 Observer 模式的高效实现。ObserverList
适用于单线程场景,高性能但非线程安全。ObserverListThreadSafe
适用于多线程场景,内部通过引用计数与锁保证安全。使用时需注意:
observer 生命周期
遍历中删除 observer
跨线程异步通知
高频事件的性能开销
在浏览器开发中,它们被广泛用于 UI 更新、后台任务通知、模块解耦等场景。
九、参考源码阅读建议
base/observer_list.h
base/observer_list_threadsafe.h
Chromium TaskScheduler 与 TaskRunner 使用场景
WeakPtr
在 Observer 生命周期管理中的使用
本文全面介绍了 Chromium base 库中 Observer 模式实现,并结合示例、对比和常见坑进行讲解,帮助开发者在浏览器或多线程 C++ 项目中安全高效地使用观察者模式。