More than code

More Than Code
The efficiency of your iteration of reading, practicing and thinking decides your understanding of the world.
  1. 首页
  2. daily
  3. 正文

Daily C/C++ 利用mutex实现简单的读写锁

2021年10月11日 866点热度 1人点赞 1条评论

Daily C/C++ 利用mutex实现简单的读写锁

之前我们有说过条件变量相关的东西,他可以帮助我们控制线程的执行

今天这里,我们就说一种简单的利用mutex和条件变量实现读写锁的方法

这里的实现其实就是CMU15445的bustub中的实现,如果有兴趣的同学可以自己去看相关的代码

首先我们要明确,我们希望实现的读写锁的性质。比如他是按照队列一个一个分配的吗?他是读者优先还是写者优先?

这里,我们要实现的读写锁是写者优先,即如果当前有写者在等待,那么新到来的读者也会被阻塞。

如果当前有写者的时候,我们又来一个写者,怎么办?如果我们始终将锁分配给写者,会不会导致饿死的现象呢?

鉴于这种情况,当目前有一个写者的时候,新来的写者将作为读者与其他读者一同竞争。当新的写者竞争到锁的时候,他就会阻塞新的读者,然后等待现有的读者结束,从而开始他自己的任务。

看起来是一个比较合理的策略,我们来看看代码

  /**
   * Acquire a write latch.
   */
  void WLock() {
    std::unique_lock<mutex_t> latch(mutex_);
    while (writer_entered_) {
      reader_.wait(latch);
    }
    writer_entered_ = true;
    while (reader_count_ > 0) {
      writer_.wait(latch);
    }
  }

  /**
   * Release a write latch.
   */
  void WUnlock() {
    std::lock_guard<mutex_t> guard(mutex_);
    writer_entered_ = false;
    reader_.notify_all();
  }

  /**
   * Acquire a read latch.
   */
  void RLock() {
    std::unique_lock<mutex_t> latch(mutex_);
    while (writer_entered_ || reader_count_ == MAX_READERS) {
      reader_.wait(latch);
    }
    reader_count_++;
  }

  /**
   * Release a read latch.
   */
  void RUnlock() {
    std::lock_guard<mutex_t> guard(mutex_);
    reader_count_--;
    if (writer_entered_) {
      if (reader_count_ == 0) {
        writer_.notify_one();
      }
    } else {
      if (reader_count_ == MAX_READERS - 1) {
        reader_.notify_one();
      }
    }
  }

其实是很简单的四块逻辑,我们一个一个看

WLock会首先判断当前有没有写者正在操作或者等待,如果有的话,那么新的写者就会在读者的条件变量中进行等待,意为等待写者

由此也可以看出,读者和写者的条件变量并不是单独给这两种角色准备的,而是根据含义来分配。如果我们在等待写者,我们就要分配到读者条件变量中。如果我们在等待读者,我们自然就要分配到写者的条件变量中。

当轮到新的写者被唤醒的时候,他会检查当前是否有写者在进行操作,因为有可能出现有多个写者在等待一个写者的情况。然后他会设置writer_entered_,这会告诉其他的线程,现在有一个写者在等待操作了。然后他就会在写者的条件变量中等待,等待当前所有的读者都结束后,他就会获取这个锁。

WUnlock则是对应的解锁,他会设置writer_entered_为false,告诉其他的线程写者的操作都已经结束了。然后在读者的条件变量上唤醒所有的读者

RLock会首先判断,如果当前有写者在等待,那么他就会进入读者的等待队列中,等待写者结束操作。或者当读者的数量到达一个限值的时候,他也会进入等待。同时,读者会维护一个reader_count_用来代表当前读者的数量

RUnlock同样也会维护读者的数量。同时他会判断,如果当前有写者在等待,同时这个读者是最后一个读者了,那么他就会唤醒这个写者。

否则的话,只有在超出读者上限的时候才会出现读者等读者的情况,这时候他会唤醒一个等待的读者线程。

基本的功能都解析完了,然后我们看看他是怎么实现我们上述的那些特性的

写者优先我们已经可以看到了,当读者发现有写者正在等待或者正在操作的时候,他会进入等待。

对于多个写者的情况,新的写者们就会在读者的条件变量中等待。一旦执行了WUnlock,唤醒了所有的读者线程,那么优先获得锁的写者就会将writer_entered_设为真,从而阻塞其他所有的线程。然后他就会在写者队列中等待读者完成任务,从而获取锁。

大概的介绍就是这样了,不得不说实现的确实非常巧妙。十分感谢Andy为我们带来这样优秀的学习资源

标签: c++
最后更新:2021年10月11日

sheep

think again

点赞
< 上一篇
下一篇 >

文章评论

  • chicken

    nb啊老板

    2021年10月12日
    回复
  • 取消回复

    COPYRIGHT © 2021 heavensheep.xyz. ALL RIGHTS RESERVED.

    THEME KRATOS MADE BY VTROIS