webRTC base模块SharedExclusiveLock读写锁实现

Linux下读写锁的实现

读写锁顾名思义就是用于读/写操作竞争的锁
有这么一种情况 一路在写资源 多路在读资源

使用之前分析过的临界锁和事件实现
临界锁的实现 http://blog.csdn.net/qq_21358401/article/details/78638668
事件的实现 http://blog.csdn.net/qq_21358401/article/details/78623793

接口实现

实现文件: webRTC/base/sharedexclusivelock.cc
文件内实现了三个类 SharedExclusiveLock SharedScope ExclusiveScope
ShareScope 和 ExclusiveScope是对SharedExclusiveLock 的封装
从名字上也可以看出 SharedScope 共享区 是读文件/资源的接口
ExclusiveScope 排他区 是写文件/资源的接口

class LOCKABLE SharedExclusiveLock {
 public:
  SharedExclusiveLock();

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

 private:
  rtc::CriticalSection cs_exclusive_; // 排他 临界锁
  rtc::CriticalSection cs_shared_; // 共享 临界锁
  rtc::Event shared_count_is_zero_; // 排他 事件
  int shared_count_; // 共享锁 计数

  RTC_DISALLOW_COPY_AND_ASSIGN(SharedExclusiveLock);
};

首先看读写锁的构造函数

SharedExclusiveLock::SharedExclusiveLock()
    : shared_count_is_zero_(true, true), // 注意Event事件shared_cound_is_zero的构造参数
      shared_count_(0) {
}

构造时指示了Event事件的构造参数时true 这也就意味着在事件没有reset之前 即使调用事件的Wait 也并不会阻塞等待
这个逻辑 正符合读写锁的逻辑

写文件/资源时  如果没有线程在读文件/资源 则直接写文件/资源
             如果有线程在读文件/资源 则等待所有读动作退出后 才写资源(也就是读写锁中shared_count_对读文件/资源的共享区计数的意义所在)

再看排他区的操作

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) { // 第一次进入 则reset事件 
                              // reset后 事件wait会阻塞等待事件set
                              // 也就是有读动作则写动作阻塞等待  
    shared_count_is_zero_.Reset();
  }
}

void SharedExclusiveLock::UnlockShared() {
  CritScope shared_scope(&cs_shared_);
  if (--shared_count_ == 0) { // 最后一个读动作也退出
                              // 事件set 使得写动作得以执行
    shared_count_is_zero_.Set();
  }
}

示例代码:

#include <iostream>
#include <memory>
#include <string>
#include <csignal>
#include "pthread.h"

#include "webrtc/base/sharedexclusivelock.h"

using namespace rtc;
using namespace std;

SharedExclusiveLock *lock;
static int val = 0;

void *thread_write(void *args) {
    int cnt = 0;
    for (; cnt < 5; cnt++) {
        lock->LockExclusive();
        val++;
        lock->UnlockExclusive();
    }
}

void *thread_read(void *args) {
    int cnt = 0;
    for (; cnt < 5; cnt++) {
        lock->LockShared();
        cout << "read val:" << val << endl;
        lock->UnlockShared();
    }
}

int main(int argc, char **argv) {
    int ret = 0;
    pthread_t t_write, t_read;

    lock = new SharedExclusiveLock();
    ret = pthread_create(&t_write, NULL, thread_write, NULL);
    if (ret < 0) {
        cout << "create thread write failed"<< endl;
        return -1;
    }

    ret = pthread_create(&t_read, NULL, thread_read, NULL);
    if (ret < 0) {
        cout << "create thread read failed"<< endl;
        return -1;
    }

    pthread_join(t_write, NULL);
    pthread_join(t_read, NULL);

    return 0;
}

执行结果一般是输出读到的都是资源数都是5或者都是0
这是因为读动作触发事件 使得写事件被阻塞 -> 读到的都是0
或者写动作快速完成 -> 读动作执行 -> 读到的都是5

git参考代码地址

https://github.com/sliver-chen/webRTCTutorial/blob/master/SharedScope/SharedScope.cpp

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值