是否要保证线程安全是底层SDK设计中的一个问题。 通常来说, API 线程安全是其易用的重要标志, 但是底层SDK往往是一个比较复杂的状态机, 如果声明了线程安全, 随之而来的是API的调用可能会来自任意线程。 现在的开发应用环境都已经普遍支持线程池, 对应用而言, 把任务交给线程池处理是比较方便的, 也比较自然。 这样的话, 对于底层API的调用可能是直接来自线程池的任意一个线程, 如果真的允许线程乱入, 那对于SDK自身状态维护, 是极大的挑战, 一般也很难处理好。
那么应该怎么在保持SDK 易用性的前提下, 同时又能让自己的状态维护尽量保持简单呢? 很容易想到的方法是转线程调用, 将来自任意线程的API调用, 转向SDK内部的工作线程, 这样,在应用的角度看来, 这个SDK是线程安全并且支持线程乱入的, 但是内部又保持了简单有序的操作。 在这里, WebRTC提供了一个极好的设计思路, 那就是PROXY。
WebRTC所暴露的native 接口的最重要的模块大概是PeerConnectionFactoryInterface和PeerConnectionInterface, 这两个接口都有各自对应的 PROXY. 让我们以PeerConnectionFactory的实现来分析PROXY的设计思路吧. 且看代码:
BEGIN_SIGNALING_PROXY_MAP(PeerConnectionFactory)
PROXY_METHOD1(void, SetOptions, const Options&)
// Can't use PROXY_METHOD5 because unique_ptr must be moved.
// TODO(tommi,hbos): Use of templates to support unique_ptr?
rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
const PeerConnectionInterface::RTCConfiguration& a1,
const MediaConstraintsInterface* a2,
std::unique_ptr<cricket::PortAllocator> a3,
std::unique_ptr<DtlsIdentityStoreInterface> a4,
PeerConnectionObserver* a5) override {
return signaling_thread_
->Invoke<rtc::scoped_refptr<PeerConnectionInterface>>(