SharedExclusiveLock 共享互斥锁

共享互斥锁,有时也被称为单写多读锁。
简单点的应用场景就是:一个写多个读。

代码来源是webrtc的SharedExclusiveLock类

// This class provides shared-exclusive lock. It can be used in cases like
// multiple-readers/single-writer model.
class SharedExclusiveLock {
 public:
  SharedExclusiveLock();

  // Locking/unlocking methods. It is encouraged to use SharedScope or
  // ExclusiveScope for protection.
  void LockExclusive();
  void UnlockExclusive();
  void LockShared();
  void UnlockShared();

 private:
  rtc::CriticalSection cs_exclusive_;
  rtc::CriticalSection cs_shared_;
  rtc::Event shared_count_is_zero_;
  int shared_count_;
};

这个是头文件,下面是cpp:

SharedExclusiveLock::SharedExclusiveLock()
    : shared_count_is_zero_(true, true),
      shared_count_(0) {
}

void SharedExclusiveLock::LockExclusive() {
  cs_exclusive_.Enter();
  shared_count_is_zero_.Wait(Event::kForever);
}

void SharedExclusiveLock::UnlockExclusive() {
  cs_exclusive_.Leave();
}

void SharedExclusiveLock::LockShared() {
  CritScope exclusive_scope(&cs_exclusive_);
  CritScope shared_scope(&cs_shared_);
  if (++shared_count_ == 1) {
    shared_count_is_zero_.Reset();
  }
}

void SharedExclusiveLock::UnlockShared() {
  CritScope shared_scope(&cs_shared_);
  if (--shared_count_ == 0) {
    shared_count_is_zero_.Set();
  }
}

至于rtc下的CriticalSection和Event,就是将windows下的互斥量和事件简单封装了一下,不贴代码也可以猜到调用了哪些方法。
下面是SharedExclusiveLock的用法:


class SharedScope {
 public:
  explicit SharedScope(SharedExclusiveLock* lock)
      : lock_(lock) {
    lock_->LockShared();
  }

  ~SharedScope() { lock_->UnlockShared(); }

 private:
  SharedExclusiveLock* lock_;
};

class ExclusiveScope {
 public:
  explicit ExclusiveScope(SharedExclusiveLock* lock)
      : lock_(lock) {
    lock_->LockExclusive();
  }

  ~ExclusiveScope() { lock_->UnlockExclusive(); }

 private:
  SharedExclusiveLock* lock_;
};

当时不是调试代码到这的, 而是画类图看到这了,盯了半小时,在记事本上画了一页之后才有个概念:
结合注释知道这是一个单写多读的锁,那么以下几点应该是可预见的:
读时不能写,写时不能读,读读是允许的
反向查了一下代码,发现在webrtc中比较常见的用法如下:

SharedExclusiveLock ss_lock_;

// 001
  SharedScope ss(&ss_lock_);
  if (ss_) {
    ss_->SetMessageQueue(NULL);

// 002
SocketServer* MessageQueue::socketserver() {
  SharedScope ss(&ss_lock_);
  return ss_;
}

// 003
  ExclusiveScope es(&ss_lock_);
  ss_ = ss ? ss : own_ss_.get();
  ss_->SetMessageQueue(this);

// 004
    {
      // Wait and multiplex in the meantime
      SharedScope ss(&ss_lock_);
      if (!ss_->Wait(static_cast<int>(cmsNext), process_io))
        return false;
    }

看了用法结合源码,分析如下:
SharedExclusiveLock有两互斥两和一个事件,外加一个共享计数
取下名字好接下来分析:互斥量A 互斥两B 事件E
互斥量A主要用于读写之间,互斥量B用于读读之间,且B这样设计是为了保证共享计数的同步
至于E,就是和A配合来保证读写同步

看下源码:
写:
LockExclusive
。。。
UnlockExclusive
过程是获取A,等待E有信号,写操作,释放A
读:
LockShared
。。。
UnlockShared
过程是:等待A,更新共享计数,释放A,读操作
作用域完了之后:更新共享计数

可以看出读和写之间的同步是通过一个互斥量A和一个事件E来保证的

当写时,读是被阻塞的,具体是因为A还被写操作持有,读会阻塞
当读时,写是被阻塞的,具体是因为事件被置为无信号,读会等待
当读时,遇到了另一个读操作,她们俩之间只会将因为共享技术有些竞争,用互斥量B解决之后,就可以读读同时进行了。

好代码一定要细细品味 冷暖自知

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值