读写锁 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 进行读写保护。
