Golang中设置awoke=true后为何还要调用runtime_doSpin
Golang中设置awoke=true后为何还要调用runtime_doSpin github.com
awoke := false
iter := 0
old := m.state
for {
// Don't spin in starvation mode, ownership is handed off to waiters
// so we won't be able to acquire the mutex anyway.
if old&(mutexLocked|mutexStarving) == mutexLocked && runtime_canSpin(iter) {
// Active spinning makes sense.
// Try to set mutexWoken flag to inform Unlock
// to not wake other blocked goroutines.
if !awoke && old&mutexWoken == 0 && old>>mutexWaiterShift != 0 &&
atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) {
awoke = true
}
runtime_doSpin()
iter++
old = m.state
continue
}
new := old
// Don't try to acquire starving mutex, new arriving goroutines must queue.
根据代码审查,自旋是为了设置 mutexWoken 标志。
但为什么在设置 awoke = true 之后,可能还会调用 runtime_doSpin?
更多关于Golang中设置awoke=true后为何还要调用runtime_doSpin的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang中设置awoke=true后为何还要调用runtime_doSpin的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go的互斥锁实现中,awoke=true和runtime_doSpin()的调用是自旋逻辑中的两个独立但相关的操作。
当awoke被设置为true时,表示当前goroutine成功设置了mutexWoken标志,通知解锁操作不要唤醒其他等待的goroutine。然而,即使成功设置了该标志,当前goroutine仍然需要继续自旋等待锁的释放。
runtime_doSpin()的作用是执行实际的自旋等待,让CPU空转一小段时间,避免立即进入休眠状态。这在锁可能很快被释放的场景下能减少上下文切换的开销。
示例代码说明这个逻辑:
// 自旋循环
for i := 0; i < maxSpins; i++ {
// 尝试设置woken标志
if !awoke && canSetWoken(state) {
if atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) {
awoke = true // 标志设置成功
}
}
// 无论是否成功设置woken标志,都需要继续自旋等待
runtime_doSpin() // 执行实际的自旋
// 重新检查锁状态
old = atomic.LoadInt32(&m.state)
if !isLocked(old) {
break // 锁已释放,尝试获取
}
}
关键点在于:
awoke=true只是标记"已成功设置woken标志"的状态runtime_doSpin()是实际的自旋等待行为- 即使woken标志设置成功,锁可能仍未释放,需要继续自旋等待
这种设计允许goroutine在自旋期间:
- 标记自己为"已唤醒"状态(避免解锁时唤醒其他goroutine)
- 同时继续积极尝试获取锁(通过自旋减少延迟)
在后续的锁获取逻辑中,awoke标志会被使用:
if awoke {
// 清除woken标志,因为当前goroutine即将获得锁
new &^= mutexWoken
}
这种分离设计确保了自旋等待和状态管理的正交性,让代码更清晰且易于维护。

