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

1 回复

更多关于Golang中设置awoke=true后为何还要调用runtime_doSpin的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go的互斥锁实现中,awoke=trueruntime_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  // 锁已释放,尝试获取
    }
}

关键点在于:

  1. awoke=true只是标记"已成功设置woken标志"的状态
  2. runtime_doSpin()是实际的自旋等待行为
  3. 即使woken标志设置成功,锁可能仍未释放,需要继续自旋等待

这种设计允许goroutine在自旋期间:

  • 标记自己为"已唤醒"状态(避免解锁时唤醒其他goroutine)
  • 同时继续积极尝试获取锁(通过自旋减少延迟)

在后续的锁获取逻辑中,awoke标志会被使用:

if awoke {
    // 清除woken标志,因为当前goroutine即将获得锁
    new &^= mutexWoken
}

这种分离设计确保了自旋等待和状态管理的正交性,让代码更清晰且易于维护。

回到顶部