【RWMutex】读写锁的实现原理

Go标准库中的RWMutex是基于Mutex实现的。RWMutex包含一个Mutex,以及四个辅助字段。

type RWMutex struct {
	w           Mutex        // 互斥锁解决多个writer的竞争
	writerSem   uint32       // writer信号量
	readerSem   uint32       // reader信号量
	readerCount atomic.Int32 // reader的数量
	readerWait  atomic.Int32 // writer等待完成的reader的数量
}

const rwmutexMaxReaders = 1 << 30

字段 w:为 writer 的竞争锁而设计;

字段 readerCount:记录当前 reader 的数量(以及是否有 writer 竞争锁);

readerWait:记录 writer 请求锁时需要等待 read 完成的 reader 的数量;

writerSem 和 readerSem:都是为了阻塞设计的信号量。

常量 rwmutexMaxReaders,定义了最大的 reader 数量。

读锁

func (rw *RWMutex) RLock() {
...
	if rw.readerCount.Add(1) < 0 {
		runtime_SemacquireRWMutexR(&rw.readerSem, false, 0)
	}
...
}

func (rw *RWMutex) RUnlock() {
...
	if r := rw.readerCount.Add(-1); r < 0 {
		rw.rUnlockSlow(r)
	}
...
}

func (rw *RWMutex) rUnlockSlow(r int32) {
...

	if rw.readerWait.Add(-1) == 0 {
		runtime_Semrelease(&rw.writerSem, false, 1)
	}
}

逻辑:加锁时,将读的数量+1,并判断+1后的数量是否为负值,为负时说明有写操作在等待,然后让读操作休眠;解锁时,读的数量-1,判断是否有写等待,有就将readerWait-1,若当前读的为最后一个,则唤醒写锁。

写锁

func (rw *RWMutex) Lock() {
...
	rw.w.Lock()
	// Announce to readers there is a pending writer.
	r := rw.readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders
	if r != 0 && rw.readerWait.Add(r) != 0 {
		runtime_SemacquireRWMutex(&rw.writerSem, false, 0)
	}
...
}

func (rw *RWMutex) Unlock() {
...

	r := rw.readerCount.Add(rwmutexMaxReaders)
...
	for i := 0; i < int(r); i++ {
		runtime_Semrelease(&rw.readerSem, false, 0)
	}
	rw.w.Unlock()
...
}

逻辑:加锁时,加互斥锁,反转readCount,让使用读锁的时候,知道有写锁在竞争,并将当前读的数量加到readerWait上,让写锁休眠;解锁时,先将readerCount转为正数,再唤醒所有的读操作,最后解开互斥锁。

注意:

  1. 锁不能复制,
  2. 重入导致死锁
    1. 连续调用写锁
    2. 读锁中调用了写锁
    3. 形成环形依赖
  3. 未释放加锁的RWMutex
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值