读锁写锁关系记录

41 阅读2分钟

在Go中,sync.RWMutex(读写互斥锁)允许多个读操作同时进行,但写操作是互斥的。它的关键方法是:

  • RLock():获取读锁,可以并发多个 goroutine 同时获取,只要没有写锁持有。
  • Lock():获取写锁,不能与任何读锁或写锁同时持有,保证独占访问。

关系总结:

  • 多个RLock()可以同时存在,只要没有Lock()(写锁)持有。
  • 一旦有任何Lock()持有(写锁),所有的RLock()Lock()都必须等待
  • 一旦有任何RLock()存在,不能执行Lock() ,因为写锁需要独占。

简单示意:

状态允许的操作
多个RLock()持有同时存在可以同时进行,相互不阻塞(读并发)
Lock()(写锁)持有其他RLock()Lock()都被阻塞
Lock(),有RLock()其他RLock()也可以继续,写锁等待直到所有RLock()释放
RLock()时调用Lock()阻塞,等待所有RLock()释放,才能获得写锁

简单理解:

  • RLock()RLock()可以同时持有
  • Lock()会等待直到所有RLock()都释放
  • 出现Lock(),其他RLock()Lock()都会暂停

sync.RWMutex(读写互斥锁) RLock 和 lock 有优先级的区别么?

sync.RWMutex 中,RLock()(读锁)和 Lock()(写锁)没有优先级的区别,它们的行为如下:

  • Lock()(写锁) :用于独占锁,获得写锁的 goroutine 会阻塞,直到没有其他读锁或写锁持有时才会获得锁。
  • RLock()(读锁) :允许多个读操作同时持有,只要没有任何写锁在持有中。如果有任何写锁正在使用,RLock() 会阻塞。

核心点:

  • 没有优先级排序sync.RWMutex 不会偏向读锁或写锁。
  • 可能发生“写饥饿” :如果持续有很多读锁(RLock())在获取,写锁(Lock())可能长时间阻塞。或者反之,如果持续有写锁,新的读锁会被阻塞。

小结:

  • RLock()Lock() 不存在优先级关系,也不会自动偏向某一方。
  • 这意味着,读操作可以连续进行,除非有写锁等待或已持有。而写操作会等待直到没有任何读锁或写锁

如果需要避免某一方饥饿,通常需要自己设计一些调度逻辑,或者使用其他同步机制。