SharedExclusiveLock 共享互斥锁

来源:互联网 发布:时空智友软件 编辑:程序博客网 时间:2024/06/16 01:30

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

代码来源是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);// 002SocketServer* 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解决之后,就可以读读同时进行了。

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

0 0