golang中的读写锁原理

读写锁特点

  • 读+读:通过
  • 读+写:阻塞
  • 写+读:阻塞
  • 写+写:阻塞
type RWMutex struct {
	w           Mutex  // held if there are pending writers
	writerSem   uint32 // 控制获取写锁的信号量
	readerSem   uint32 // 控制获取读锁的信号量
    
	readerCount int32  
	readerWait  int32  
}

func (rw *RWMutex) RLock() {
	if atomic.AddInt32(&rw.readerCount, 1) < 0 {
		runtime_SemacquireMutex(&rw.readerSem, false, 0)
	}
}

func (rw *RWMutex) RUnlock() {
	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")
	}
	// 每次释放读锁,readerWait 都会减1,直到为0就释放 writerSem 信号量
	if atomic.AddInt32(&rw.readerWait, -1) == 0 {
		runtime_Semrelease(&rw.writerSem, false, 1)
	}
}

func (rw *RWMutex) Lock() {
	rw.w.Lock()
	// r 就是 readerCount 原先的值
    // readerCount 减去一个很大的值,就是表明写锁已经加上了,后续的读锁请求将阻塞
	r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
    // 获取了写锁,还要等待所以的读锁全部释放
    // readerWait + r 其实就是还有多少个读锁没有释放,
    //    如果不为0,则需要等待信号量
    //    如果为0,则直接成功,不能等待信号量
	if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
		runtime_SemacquireMutex(&rw.writerSem, false, 0)
	}
}

func (rw *RWMutex) Unlock() {
	// 将 readerCount 恢复正常值,也就是读锁的个数
	r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
	if r >= rwmutexMaxReaders {
		throw("sync: Unlock of unlocked RWMutex")
	}
	// 向所以的读锁释放信号量
	for i := 0; i < int(r); i++ {
		runtime_Semrelease(&rw.readerSem, false, 0)
	}
	rw.w.Unlock()
}

首先是获取读锁和释放读锁,在不考虑其他的情况下,直接加减readerCount即可。

获取写锁的过程是互斥的,因此需要一个互斥锁来加持;拿到了互斥锁之后,就意味着抢到了写锁,如果此时已经有协程在使用读锁,那么需要等到这些读锁全部释放,对应的信号量为writerSem

读写锁的关键是,既要操作信号量,但是有可能根本就没有对方,所以又不能盲目的操作,所以先判断一个数量,然后再操作。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值