面试题答案
一键面试1. RWMutex内部数据结构
Go语言的RWMutex
主要包含两个字段:
w
:一个信号量,表示写锁。当有写操作时,w
的值会大于0,其他读写操作需要等待。readerCount
:表示当前正在进行读操作的数量。readerWait
:记录在写操作开始时,已经存在的读操作数量,用于写操作完成后唤醒等待的读操作。
2. 写锁实现机制
当一个写操作尝试获取写锁时:
- 首先通过
atomic.AddInt32
将readerCount
减去一个很大的负数(-rwmutexMaxReaders
),这样后续的读操作尝试获取读锁时会发现readerCount
为负数,从而等待写操作完成。 - 然后获取
w
信号量,如果获取成功,则写锁获取成功,可以进行写操作。 - 写操作完成后,通过
atomic.AddInt32
将readerCount
加上rwmutexMaxReaders
,并释放w
信号量,唤醒等待的读操作。
3. 读锁实现机制
当一个读操作尝试获取读锁时:
- 首先通过
atomic.AddInt32
增加readerCount
的值,表示有新的读操作开始。 - 检查
readerCount
是否为负数,如果是负数,说明有写操作正在进行或者等待,读操作需要等待。 - 读操作完成后,通过
atomic.AddInt32
减少readerCount
的值。如果减少后readerCount
的值为0,且有写操作在等待(readerWait
大于0),则唤醒等待的写操作。
4. 避免写锁饥饿问题
- 读锁限流:当写操作开始时,通过将
readerCount
减去rwmutexMaxReaders
,限制后续读操作的获取,使得写操作不会因为持续的读操作而饥饿。 - 公平唤醒:写操作完成后,会根据
readerWait
的值唤醒等待的读操作,确保读操作按照等待顺序被唤醒,进一步保证写操作的公平性。
5. 读锁高效共享资源
- 轻量级同步:读锁之间通过
atomic.AddInt32
和atomic.LoadInt32
等原子操作来维护readerCount
,这些操作开销相对较小,在高并发读场景下能够高效共享资源。 - 并发读支持:多个读操作可以同时获取读锁,只要没有写操作进行,读操作之间不会相互阻塞,从而提高了并发读的效率。