You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Peterson算法实现出现疑似死锁,疑与编译器优化相关

Peterson算法在Go中出现假死问题的原因与解决方法

你的判断完全正确——这个假死问题就是编译器优化+CPU缓存一致性导致的,和所谓的“良性数据竞争”风险直接相关。

问题根源

Peterson算法的正确性依赖于三个关键操作的内存可见性和执行顺序:

  1. 线程设置自己的flag为true
  2. 设置victim为自己的ID
  3. 循环检查对方的flag和当前victim值

但在Go中,没有同步机制的情况下,编译器可能会对指令进行重排(比如把m.victim = id移到m.flag[id] = true之前),或者CPU会将变量缓存到寄存器/本地缓存中,导致一个goroutine对flag或victim的修改,另一个goroutine无法及时看到。最终循环条件一直为true,出现无限停滞的假死状态。

而当你用原子操作存储/加载victim时,原子操作自带内存屏障,强制了内存可见性和指令顺序,所以问题消失。

解决方法

1. 临时禁用编译器优化(不推荐用于生产)

如果只是验证问题,可以通过编译选项禁用优化和内联:

go run -gcflags="-N -l" your_program.go

-N 禁用所有编译器优化,-l 禁用函数内联。但这只是临时方案,因为即使禁用编译器优化,CPU的缓存一致性问题依然可能导致可见性问题,无法从根本上保证正确性。

2. 用内存同步机制修复算法(推荐)

Go没有volatile关键字,正确的做法是用sync/atomic包来保证共享变量的内存可见性和原子性。修改后的代码如下:

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
    "runtime"
)

type mutex struct {
    flag   [2]atomic.Bool
    victim atomic.Int32
}

func (m *mutex) lock(id int) {
    m.flag[id].Store(true)
    m.victim.Store(int32(id))
    // 循环检查:对方flag为true,且victim是当前id时等待
    for m.flag[1-id].Load() && m.victim.Load() == int32(id) {
        runtime.Gosched() // 让出CPU,避免空耗资源
    }
}

func (m *mutex) unlock(id int) {
    m.flag[id].Store(false)
}

func main() {
    var wg sync.WaitGroup
    var mu mutex
    var cpt atomic.Int32
    n := 100000

    for i := 0; i < 2; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            for j := 0; j < n; j++ {
                mu.lock(id)
                cpt.Add(1)
                mu.unlock(id)
            }
        }(i)
    }

    wg.Wait()
    fmt.Println(cpt.Load())
}

这里做了两个关键修改:

  • 把flag和victim换成原子类型,所有读写都用Load()和Store()操作,这些操作会插入内存屏障,保证修改对其他goroutine可见,同时阻止指令重排。
  • 计数器cpt也换成了atomic.Int32,彻底消除了原本的数据竞争(之前计数器值正确只是侥幸,数据竞争会导致未定义行为)。

另外,空循环等待时加入runtime.Gosched(),让当前goroutine让出CPU,避免空耗资源。

内容的提问来源于stack exchange,提问作者Taki Eddine MEKHALFA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 00:54:28