proxy分析

在webrtc中,许多重要的对象实际上都是“代理对象”,如PeerConnection, PeerConnectionFactory,等等,可以看下PeerConnectionFactory的源代码:

rtc::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory() {
  rtc::scoped_refptr<PeerConnectionFactory> pc_factory(    
      new rtc::RefCountedObject<PeerConnectionFactory>()); 

  RTC_CHECK(rtc::Thread::Current() == pc_factory->signaling_thread());

  if (!pc_factory->Initialize()) {  
    return nullptr;
  }
  return PeerConnectionFactoryProxy::Create(pc_factory->signaling_thread(),                                     pc_factory);
}

从代码可以看出,创建PeerConnectionFactory实际上返回的是PeerConnectionFactoryProxy对象。那这么做有什么用呢?从PeerConnectionFactoryProxy::Create(pc_factory->signaling_thread(), pc_factory); 中可以看到,Create的还有一个参数是pc_factory->signaling_thread(),猜一下也知道,这是为了解决多线程问题的。其实,他是为了保证所有的proxy对象的操作都在singaling线程中,当在另一个线程调用了proxy对象的方法时,proxy对象会将该方法的操作包装成一个message,发送给singaling线程,然后阻塞等待singaling线程中执行完成。

下面可以看一下它的源码是如何实现的,为了简单起见,使用MediaStream为例说明,

rtc::scoped_refptr<MediaStreamInterface>
PeerConnectionFactory::CreateLocalMediaStream(const std::string& label) {
  RTC_DCHECK(signaling_thread_->IsCurrent());
  return MediaStreamProxy::Create(signaling_thread_,
                                  MediaStream::Create(label));
}

MediaStreamProxy实际上是由一个宏生成的,如下:

BEGIN_SIGNALING_PROXY_MAP(MediaStream)
  PROXY_CONSTMETHOD0(std::string, label)
  PROXY_METHOD0(AudioTrackVector, GetAudioTracks)
  PROXY_METHOD0(VideoTrackVector, GetVideoTracks)
  PROXY_METHOD1(rtc::scoped_refptr<AudioTrackInterface>,
                FindAudioTrack, const std::string&)
  PROXY_METHOD1(rtc::scoped_refptr<VideoTrackInterface>,
                FindVideoTrack, const std::string&)
  PROXY_METHOD1(bool, AddTrack, AudioTrackInterface*)
  PROXY_METHOD1(bool, AddTrack, VideoTrackInterface*)
  PROXY_METHOD1(bool, RemoveTrack, AudioTrackInterface*)
  PROXY_METHOD1(bool, RemoveTrack, VideoTrackInterface*)
  PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
  PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
END_SIGNALING_PROXY()

}

把这些宏都展开,如下(为避免太长砍掉了很多函数):

class MediaStreamProxy : public MediaStreamInterface {                                  \
protected:                                                             
    typedef MediaStreamInterface C;  

    MediaStreamProxy(rtc::Thread* signaling_thread, C* c)                      
      : signaling_thread_(signaling_thread), c_(c) {}                    
    ~MediaStreamProxy() {                                                        
      MethodCall0<MediaStreamProxy, void> call(                                 
        this, &MediaStreamProxy::Release_s);                                 
        call.Marshal(signaling_thread_);                                   
    }                                                                    

public:                                                              
    static rtc::scoped_refptr<C> Create(rtc::Thread* signaling_thread, C* c) { 
        return new rtc::RefCountedObject<MediaStreamProxy>(                         
            signaling_thread, c);                                         
    }

    std::string label() const override {                         
        ConstMethodCall0<C, std::string> call(c_.get(), &C::label); 
        return call.Marshal(signaling_thread_);            
    }

    AudioTrackVector GetAudioTracks() override {                           
        MethodCall0<C, AudioTrackVector> call(c_.get(), &C::GetAudioTracks); 
        return call.Marshal(signaling_thread_);       
    }

private:
    void Release_s() {
        c_ = NULL;
    }
    mutable rtc::Thread* signaling_thread_;
    rtc::scoped_refptr<C> c_;
};

我们以GetAudioTracks()函数分析,可见它实际上是调用
MethodCall0的Marshal方法,MethodCall0的实现如下:

template <typename C, typename R>
class MethodCall0 : public rtc::Message,
                    public rtc::MessageHandler {
 public:
  typedef R (C::*Method)();
  MethodCall0(C* c, Method m) : c_(c), m_(m) {}

  R Marshal(rtc::Thread* t) {
    internal::SynchronousMethodCall(this).Invoke(t);
    return r_.value();
  }

 private:
  void OnMessage(rtc::Message*) {  r_.Invoke(c_, m_); }

  C* c_;
  Method m_;
  ReturnType<R> r_;
};

MethodCall0的Marshal中实际上调用SynchronousMethodCall的Invoke():

class SynchronousMethodCall
    : public rtc::MessageData,
      public rtc::MessageHandler {
 public:
  explicit SynchronousMethodCall(rtc::MessageHandler* proxy)
      : e_(), proxy_(proxy) {}
  ~SynchronousMethodCall() {}

  void Invoke(rtc::Thread* t) {
    if (t->IsCurrent()) {
      proxy_->OnMessage(NULL);
    } else {
      e_.reset(new rtc::Event(false, false));
      t->Post(this, 0);
      e_->Wait(rtc::Event::kForever);  //阻塞,直到e_->Set();
    }
  }

 private:
  void OnMessage(rtc::Message*) { proxy_->OnMessage(NULL); e_->Set(); }  //在另一个线程执行proxy_->OnMessage(真正的任务),然后调用e_->Set();解除等待线程的阻塞
  std::unique_ptr<rtc::Event> e_;
  rtc::MessageHandler* proxy_;
};

从Invoke中可以看出,它先判断当前线程是不是t(即signaling线程),如果是则直接执行,若不是,则将该消息发送至signaling线程并等待执行完成。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
proxy_qlen是一个Linux内核中的网络模块,其作用是限制网络数据包的队列长度。其源码位于文件路径为`net/sched/sch_api.c`和`include/net/sch_generic.h`。下面是其源码的分析: 1.在`sched/sch_api.c`中,proxy_qlen的实现是通过调用函数`qdisc_create_dflt()`来创建一个默认的队列规则,并将其作为子规则添加到给定的网络设备的根规则中。其中的`qdisc`是队列规则的数据结构,包含了队列的一些参数和操作函数。 2.`qdisc_create_dflt()`函数首先通过调用`qdisc_create()`函数来创建一个队列规则,并初始化其参数和操作函数。然后,它调用`qdisc_add()`函数将该队列规则添加到给定的父规则中。在proxy_qlen的实现中,父规则是网络设备的根规则。 3.`qdisc`的操作函数包括了队列的入队和出队操作,以及队列的状态查询等操作。在proxy_qlen中,其主要操作函数是`proxy_qlen_enqueue()`和`proxy_qlen_dequeue()`,用来限制数据包的队列长度。 4.`proxy_qlen_enqueue()`函数在将数据包加入队列之前,首先检查队列长度是否超过了设定的最大值。如果超过了,就将队列中最早的数据包删除。然后再将新的数据包加入队列。 5.`proxy_qlen_dequeue()`函数则是在从队列中取出数据包时,将队列长度减1。 6.在`include/net/sch_generic.h`中,定义了`struct Qdisc`和`struct sk_buff`等数据结构,以及`proxy_qlen_enqueue()`和`proxy_qlen_dequeue()`等操作函数的原型。 总之,proxy_qlen是一个简单但实用的网络模块,可以限制网络数据包的队列长度,避免过长的队列导致网络性能下降。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值