跳到正文
Always Exploring
Go back

Go的sync.RWMutex

为什么需要锁?(锁就像一把钥匙,只有一个协程得到并打开共享资源的门)

解决并发访问共享资源时,出现的数据竞争和并发异常问题

如何设计和实现

首先定义结构体,需要

  1. 字段state int32类型来表示锁状态(0代表锁未持有,1代表锁已经被某个协程持有),使用atomic的cas来更新state字段,标记是否获取锁
  2. 需要等待队列queue存放阻塞goroutine(先入先出),依次被唤醒,唤醒后g需要争抢获取锁;
  3. 唤醒和挂起都需要cpu开销,可以插入队列前先自旋抢锁,得到更高的吞吐量,但不能一直自旋,也需要记录自旋次数字段spin
  4. 信号量字段来唤醒等待的goroutine获取锁
  5. 进一步优化,释放锁后新创建g1和唤醒队首的g2争抢锁,往往新创建g1会获取锁,因为新创建在cpu运行+数量比较多 可能导致队列中g一直获取不到锁,造成尾部延时;增加互斥锁状态模式字段,表示正常/饥饿状态,如果一个等待goroutine超过1ms还没有获取锁切换到饥饿状态,互斥锁解锁后优先让队首g获取,新创建g直接插入队尾。如果g是队列最后一个元素or等待时间小于1ms会从饥饿状态切换正常状态。
type RWMutex struct {
    w           Mutex  // 一个互斥锁的字段,用户进行写时加互斥锁
    writerSem   uint32 // 一个writer的信号量,类似互斥锁中的信号量
    readerSem   uint32 // 一个reader的信号量,类似互斥锁中的信号量
    readerCount int32  // 两种作用,1:标记有多少拿到读锁的reader,2:是否有writer需要竞争
    readerWait  int32  // writer需要等待读锁解锁的reader的数量
}

const rwmutexMaxReaders = 1 << 30 // 最大reader的上限。即最多有多少的reader同时能拿到读锁

Share this post on:

Previous Post
云仓inbound面试准备
Next Post
母亲的话&自己思考