读写锁 RWMutex
读操作是天生的幂等操作,因为不涉及到数据的修改,如果在一个读多写少的场景使用普通的互斥锁,每个读、写操作都要加索,会影响性能。
type RWMutex struct {w Mutex // held if there are pending writerswriterSem uint32 // semaphore for writers to wait for completing readersreaderSem uint32 // semaphore for readers to wait for completing writersreaderCount atomic.Int32 // number of pending readersreaderWait atomic.Int32 // number of departing readers
}// Happens-before relationships are indicated to the race detector via:
// - Unlock -> Lock: readerSem
// - Unlock -> RLock: readerSem
// - RUnlock -> Lock: writerSem
w
:复用互斥锁。writerSem
和readerSem
:信号量,分别用于写等待读和读等待写。readerCount
表示当前正在执行的读 goroutine 数量,以及是否有 writer 竞争锁。readerWait
表示写 goroutine 被阻塞时需要等待完成的读 goroutine 数量。
RWMutex
复用 Mutex
,因此有与 Mutex
一样的问题:
- 无法实现可重入锁。
- 可能锁会被其他 goroutine 释放。
常见的错误场景:- Lock / Unlock 或 RLock / RUnlock不是成对出现
- Copy 已使用的 RWMutex(不可以复制)
原因:RWMutex 是一个有状态的字段,在并发环境下,状态时时在变化。
- 重入
- 死锁
RWMutex
适用在读多写少的场景,最常见的就是 map 有并发读写问题,用 RWMutex
进行读写保护。