欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解golang RWMutex读写互斥锁源码分析

程序员文章站 2022-04-10 15:32:59
针对golang 1.9的sync.rwmutex进行分析,与golang 1.10基本一样除了将panic改为了throw之外其他的都一样。 rwmutex是读写互...

针对golang 1.9的sync.rwmutex进行分析,与golang 1.10基本一样除了将panic改为了throw之外其他的都一样。

rwmutex是读写互斥锁。锁可以由任意数量的读取器或单个写入器来保持。

rwmutex的零值是一个解锁的互斥锁。

以下代码均去除race竞态检测代码

源代码位置:sync\rwmutex.go

结构体

type rwmutex struct {
  w      mutex // 互斥锁
  writersem  uint32 // 写锁信号量
  readersem  uint32 // 读锁信号量
  readercount int32 // 读锁计数器
  readerwait int32 // 获取写锁时需要等待的读锁释放数量
}

常量

const rwmutexmaxreaders = 1 << 30  // 支持最多2^30个读锁

方法

lock

提供写锁操作.

func (rw *rwmutex) lock() {
  // 竞态检测
 if race.enabled {
 _ = rw.w.state
 race.disable()
 }
 // 使用mutex锁
 rw.w.lock()
 // announce to readers there is a pending writer.
 r := atomic.addint32(&rw.readercount, -rwmutexmaxreaders) + rwmutexmaxreaders
 // wait for active readers.
 if r != 0 && atomic.addint32(&rw.readerwait, r) != 0 {
 runtime_semacquire(&rw.writersem)
 }
 // 竞态检测
 if race.enabled {
 race.enable()
 race.acquire(unsafe.pointer(&rw.readersem))
 race.acquire(unsafe.pointer(&rw.writersem))
 }
}

rlock

提供读锁操作,

func (rw *rwmutex) rlock() {
  // 竞态检测
 if race.enabled {
 _ = rw.w.state
 race.disable()
 }
 // 每次goroutine获取读锁时,readercount+1
  // 如果写锁已经被获取,那么readercount在-rwmutexmaxreaders与0之间,这时挂起获取读锁的goroutine,
  // 如果写锁没有被获取,那么readercount>0,获取读锁,不阻塞
  // 通过readercount判断读锁与写锁互斥,如果有写锁存在就挂起goroutine,多个读锁可以并行
 if atomic.addint32(&rw.readercount, 1) < 0 {
 // 将goroutine排到g队列的后面,挂起goroutine
 runtime_semacquire(&rw.readersem)
 }
 // 竞态检测
 if race.enabled {
 race.enable()
 race.acquire(unsafe.pointer(&rw.readersem))
 }
}

rlocker

可以看到rwmutex实现接口locker.

type locker interface {
 lock()
 unlock()
}

而方法rlocker就是将rwmutex转换为locker.

func (rw *rwmutex) rlocker() locker {
 return (*rlocker)(rw)
}

总结

读写互斥锁的实现比较有技巧性一些,需要几点

  1. 读锁不能阻塞读锁,引入readercount实现
  2. 读锁需要阻塞写锁,直到所以读锁都释放,引入readersem实现
  3. 写锁需要阻塞读锁,直到所以写锁都释放,引入wirtersem实现
  4. 写锁需要阻塞写锁,引入metux实现

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。