RWMutex的实现原理

March 3, 2018

 

使用场景

读写锁适用于读多写少的场景。基础特性包括:

  • RLock被reader占用时,Lock(/WLock)会被block。反之依然
  • RLock被占用时,其他读线程也可以获取到RLock。即允许多个reader同时访问共享资源
  • WLock同一时间只能被一个routine/thread获取

根据不同的优先级策略,可以有不同的实现方案:

  • 读优先(Read-preferring RW locks)

    读优先允许最大量的并发,但是竞争激烈时可能导致write-starvation。因为读多写少的场景下,如果读请求的优先级更高,写锁获取成功的概率就更低了。

  • 写优先(Write-preferring RW locks)

    为了避免write-starvation的情况出现,给WLock的优先级更高,如果RLock已经被占用,那么WLock也将会在block中, 此时后续的新到的RLock调用也将被block,直到RLock被释放,WLock被writer获取成功后释放。

    对比读优先,所允许的并发量相对要小一些。且实现更为复杂,性能也相对也要差一些。

  • 总结:A good way to think about it is RWMutex is a Mutex with a reader counter. RLock increments the counter while RUnlock decrements it. A call to Lock will block as long as that counter is > 0.

实现原理

一些大致的实现思路

思路一

一个写锁(mutex)保证writer互斥

一个读锁和计数器实现读锁。读锁用户维护计数器的准确性。计数器用于多个reader计数

读优先的实现:

Loading...

思路二

使用锁和条件变量

Loading...

golang的实现

为避免writer被饿死,RWMutex中至少需要记录三个信息:

  • 使用中的reader计数器:a
  • writer请求中/使用中的标志:b
  • 挂起在writer之后的reader:c

golang用两个变量包括了以上三部分信息,具体见golang的实现(忽略race部分)

Loading...

参考

See all postsSee all posts