Go 标准库源码分析 - sync包的RWMutex

RWMutex 为读写锁,适用于读多写少的场景,可以同时有多个goroutine对临界区加读锁,此时写操作的goroutine被阻塞;同一时刻仅能有一个goroutine获得写锁,此时其他写操作和读操作的goroutine被阻塞。

一、数据结构

type RWMutex struct {
	w           Mutex  // 互斥锁
	writerSem   uint32 // 写信号量
	readerSem   uint32 // 读信号量
	readerCount int32  // 读锁计数器
	readerWait  int32  // 加写锁前需要等待释放的读锁数量
}

 二、使用方法

1. RLock:加读锁

func (rw *RWMutex) RLock() {
    // 获取读锁后,读锁计数器+1
    // 若readerCount+1后小于0,意味着有写锁被获取,此时读操作不能进行被挂起
	if atomic.AddInt32(&rw.readerCount, 1) < 0 {
		runtime_SemacquireMutex(&rw.readerSem, false, 0)
	}
}

2. RUnlock:解读锁

func (rw *RWMutex) RUnlock() {
    // 读锁计数器-1,并根据返回的值进行下一步操作
	if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {,
		rw.rUnlockSlow(r)
	}
}

func (rw *RWMutex) rUnlockSlow(r int32) {
    // 第一种情况为上锁前先解锁,第二种情况为先上写锁再解读锁,均抛出异常
	if r+1 == 0 || r+1 == -rwmutexMaxReaders {
		throw("sync: RUnlock of unlocked RWMutex")
	}
	// 读锁释放完毕后,通知写锁
	if atomic.AddInt32(&rw.readerWait, -1) == 0 {
		runtime_Semrelease(&rw.writerSem, false, 1)
	}
}

3. Lock:加写锁

func (rw *RWMutex) Lock() {
	// 上锁
	rw.w.Lock()
	// 将readerCount设为负数,表明有写操作在等待
	r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
	// r != 0即此时还有读操作在进行,则挂起当前goroutine等待读锁释放
	if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
		runtime_SemacquireMutex(&rw.writerSem, false, 0)
	}
}

4. Unlock:解写锁

func (rw *RWMutex) Unlock() {
	// 通知表明此时读锁可被获取
	r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
    // 未加写锁而解写锁,抛出异常
	if r >= rwmutexMaxReaders {
		throw("sync: Unlock of unlocked RWMutex")
	}
	// 唤醒等待读锁的goroutine
	for i := 0; i < int(r); i++ {
		runtime_Semrelease(&rw.readerSem, false, 0)
	}
	// 解锁,此时其他goroutine可获得写锁
	rw.w.Unlock()
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值