WebRTC 临界锁实现

本文所有源码均基于 WebRTC M85 (branch-heads/4183) 版本进行分析。

在阅读 WebRTC 源码过程中,经常可以看到 rtc::CritScope 相关的代码调用,例如:

void RtpVideoSender::SetFecAllowed(bool fec_allowed) {

  rtc::CritScope cs(&crit_); // rtc::CriticalSection crit_;
  fec_allowed_ = fec_allowed;
}

笔者目前的主力语言还不是 C++,所以第一次见到这种加锁机制还挺新鲜的。事实上笔者刚开始甚至以为这只是创建了一个 cs 变量,然后什么都不做,不知道这样的代码有什么意义。

但这其实是 C++ 编程的小技巧。我们先来看看 rtc::CritScope 的具体实现:

// CritScope 只有构造函数和析构函数两个定义;
// CriticalSection 在不同平台上的实现不一样,
// 对于 POSIX 而言实现为 mutable pthread_mutex_t mutex_;
CritScope::CritScope(const CriticalSection* cs) : cs_(cs) {
  cs_->Enter(); // pthread_mutex_lock(&mutex_);
}
CritScope::~CritScope() {
  cs_->Leave(); // pthread_mutex_unlock(&mutex_);
}

在 C++ 中,函数内部的局部变量会在该函数退出时进行析构(不论是否有异常)。通过在局部变量的构造函数中加锁,在析构函数中解锁,可以有效创造出一段函数生命周期内的临界区,而不用撰写类似 Java ReentrantLock 的 try-finally 释放锁的冗余代码:

class X {
  private final ReentrantLock lock = new ReentrantLock();
  // other definitions...

  public void m() {
    lock.lock();  // block until condition holds
    try {
      // method body...
    } finally {
      lock.unlock()
    }
  }
}

更进一步来说,这其实是 C++ RAII(资源获取即初始化,Resource Acquisition IInitialization)机制的一种使用场景。RAII 可以保证在释放资源时不受到异常退出的影响(即使发生了异常,也能正确释放资源);同时还能预防编码过程忘记释放资源的行为。在笔者看来,RAII 是比 Golang 的 defer 机制更加简洁的存在,哈哈。

从 WebRTC M86 (branch-heads/4240) 版本开始 rtc::CritScope 被废弃,改为使用新的 webrtc::Mutex 实现。这是因为前者为递归锁(可重入),存在一些难以解决的问题 1;需要改为非递归锁(不可重入)。

  1. 参考:Issue 11567: Refactor webrtc to use a non-recursive CriticalSection 

作者:mthli;来源:WebRTC 学习指南
链接:https://webrtc.mthli.com/code/criticalsection/

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论