type Mutex struct {
	state int32 // mutex status
	sema  uint32 // 用于阻塞唤醒 goroutinue的信号量
}


type Locker interface {
	Lock()
	Unlock()
}


const (
	mutexLocked = 1 << iota // mutex 已锁定
	mutexWoken // 有 waiter 被唤醒
	mutexStarving // mutex 处于饥饿模式
	mutexWaiterShift = iota // waiter 数量的偏移量
	starvationThresholdNs = 1e6 // 切换到饥饿模式的阈值,单位纳秒
)

state代表锁的不同状态

  • mutexLocked 锁定状态
  • mutexWaked 唤醒状态
  • mutextStarving 饥饿状态

锁有两种状态:正常模式和饥饿状态

正常模式 在正常模式下,waiter按照FIFO顺序排队,但是被唤醒的的waiter并不拥有mutex,而是与新到达的goroutinue竞争mutex的所有权。新到达的goroutinue具有优势(它们已经在CPU运行),并且可能有很多,因此被i唤醒的waiter很有可能竞争失败。在这种情况下,它会重新排到等待队列的前面。为了减少这种情况的出现,一旦Grououtinue超过1ms没有获取到锁,它就会将当前互斥锁切换饥饿模式,防止部分Goroutinue被饿死。 饥饿模式 在饥饿模式下,mutex的u所有权直接从解锁的goroutinue移交给队列最前面的waiter,新到达的goroutine不会获取mutex,即使是解锁状态,也不会进行自旋。相反,他们会将自已排到等待队列的末尾。如果一个waiter获得了mutex的所有权,并且有如下条件

  • 它是队列中的最后一个waiter
  • 等待的时间少于1ms mutex将切换回正常操作模式。 正常模式具有更好的性能,因为一个goroutinueo可以连续多次获取mutex,即使有阻塞的waiter,饥饿模式对于防止尾部延迟的病态情况非常重要。