### 说明 1. 信号量 其本质是一个整数,并关联两个操作: 申请acquire(也称为 wait、decrement 或 P 操作) 释放release(也称 signal、increment 或 V 操作) ### 锁的定义 ```go // A Locker represents an object that can be locked and unlocked. type Locker interface { Lock() Unlock() } ``` 在goalng中如果实现了Lock和Unlock方法,那么它就可以被称为锁。 #### RWMutex 的结构 ``` ~~~ type RWMutex struct { w Mutex // 控制多个写入的互斥量 writerSem uint32 // 写入操作的信号量 readerSem uint32 // 读取操作的信号量 readerCount int32 // 当前读操作数 readerWait int32 // 写入操作等待读操作数 } ~~~ ``` 主要方法是下面标注的 4 个 ![](https://img.kancloud.cn/3c/5d/3c5db3e3e12e3872d0c1eedc20a88ca4_768x778.png) 有一个常量: ~~~ const rwmutexMaxReaders = 1 << 30 ~~~ ### 1. 首先是申请读锁 ~~~ func (rw *RWMutex) RLock() { if race.Enabled { _ = rw.w.state race.Disable() } if atomic.AddInt32(&rw.readerCount, 1) < 0 { // A writer is pending, wait for it. runtime_SemacquireMutex(&rw.readerSem, false, 0) } if race.Enabled { race.Enable() race.Acquire(unsafe.Pointer(&rw.readerSem)) } } ~~~ 忽略前4行的竞态检测; 当有协程申请读锁时,readerCount 就会加一,如果小于 0,就会等待写锁释放(结合申请写锁部分就明白为什么是小于 0); ~~~ runtime_SemacquireMutex //这个方法是一个runtime的方法,会一直等待传入的s出现>0的时候 ~~~ ### 释放读锁 ~~~ // RUnlock undoes a single RLock call; // it does not affect other simultaneous readers. // It is a run-time error if rw is not locked for reading // on entry to RUnlock. func (rw *RWMutex) RUnlock() { if race.Enabled { _ = rw.w.state race.ReleaseMerge(unsafe.Pointer(&rw.writerSem)) race.Disable() } if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 { // Outlined slow-path to allow the fast-path to be inlined rw.rUnlockSlow(r) } if race.Enabled { race.Enable() } } ~~~ 主要逻辑中,readerCount 减一,如果值小于 0,调用了另一个方法(正常使用释放读锁不会出现小于 0 的情况): ~~~ func (rw *RWMutex) rUnlockSlow(r int32) { if r+1 == 0 || r+1 == -rwmutexMaxReaders { race.Enable() throw("sync: RUnlock of unlocked RWMutex") } // A writer is pending. if atomic.AddInt32(&rw.readerWait, -1) == 0 { // The last reader unblocks the writer. runtime_Semrelease(&rw.writerSem, false, 1) } } ~~~ r + 1 的值等于 0,说明在没有加读锁的情况下申请了释放读锁; r + 1 的值等于常量值,说明在申请写锁后释放读锁(参考申请写锁);