109 lines
2.8 KiB
Go
109 lines
2.8 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"sync"
|
||
"sync/atomic"
|
||
"time"
|
||
)
|
||
|
||
// =============== ABA 问题演示(增强时序稳定性) ===============
|
||
func demoABAProblem() {
|
||
var value int32 = 100
|
||
var wg sync.WaitGroup
|
||
ready := make(chan struct{}) // 同步信号:确保 A 先读取
|
||
|
||
wg.Add(2)
|
||
|
||
// Goroutine A: 读取初始值后等待信号
|
||
go func() {
|
||
defer wg.Done()
|
||
old := atomic.LoadInt32(&value) // 读取到 100
|
||
<-ready // 等待 B 完成 ABA 修改
|
||
if atomic.CompareAndSwapInt32(&value, old, 200) {
|
||
fmt.Println("⚠️ ABA 问题触发: CAS 成功!但值曾被篡改 (100→150→100)")
|
||
} else {
|
||
fmt.Println("❌ 未复现 ABA(调度异常)")
|
||
}
|
||
}()
|
||
|
||
// Goroutine B: 执行 A→B→A 修改
|
||
go func() {
|
||
defer wg.Done()
|
||
time.Sleep(5 * time.Millisecond) // 确保 A 已读取
|
||
atomic.StoreInt32(&value, 150) // A→B
|
||
atomic.StoreInt32(&value, 100) // B→A
|
||
close(ready) // 通知 A 执行 CAS
|
||
}()
|
||
|
||
wg.Wait()
|
||
fmt.Printf("最终值: %d (ABA 发生时应为 200)\n", value)
|
||
}
|
||
|
||
// =============== 安全方案:位域编码防 ABA ===============
|
||
// 64位结构: [高32位: 版本号] | [低32位: 实际值]
|
||
type VersionedInt32 struct {
|
||
data int64 // 原子存储单元
|
||
}
|
||
|
||
// 合并值与版本号
|
||
func pack(val, ver int32) int64 {
|
||
return (int64(ver) << 32) | int64(uint32(val))
|
||
}
|
||
|
||
// 拆解:返回 (值, 版本号)
|
||
func unpack(data int64) (val int32, ver int32) {
|
||
return int32(data), int32(data >> 32) // 低32位=值, 高32位=版本
|
||
}
|
||
|
||
// 安全读取当前值
|
||
func (v *VersionedInt32) Load() int32 {
|
||
val, _ := unpack(atomic.LoadInt64(&v.data)) // 取第一个返回值
|
||
return val
|
||
}
|
||
|
||
// 带版本号的原子 CAS(彻底规避 ABA)
|
||
func (v *VersionedInt32) CAS(oldVal, newVal int32) bool {
|
||
for {
|
||
current := atomic.LoadInt64(&v.data)
|
||
curVal, curVer := unpack(current)
|
||
|
||
if curVal != oldVal {
|
||
return false // 值已变更,拒绝更新
|
||
}
|
||
|
||
// 构造新状态:值更新 + 版本号+1
|
||
newState := pack(newVal, curVer+1)
|
||
|
||
if atomic.CompareAndSwapInt64(&v.data, current, newState) {
|
||
return true
|
||
}
|
||
// 失败则重试
|
||
}
|
||
}
|
||
|
||
func main() {
|
||
fmt.Println("=== ABA 问题演示(通道同步确保时序) ===")
|
||
demoABAProblem()
|
||
|
||
fmt.Println("\n=== 安全方案验证(位域编码) ===")
|
||
vv := &VersionedInt32{data: pack(100, 0)} // 初始值=100, 版本=0
|
||
|
||
// 首次 CAS:100 → 200
|
||
if vv.CAS(100, 200) {
|
||
val := vv.Load()
|
||
_, ver := unpack(atomic.LoadInt64(&vv.data))
|
||
fmt.Printf("✅ CAS 成功 | 值: %d, 版本: %d\n", val, ver)
|
||
}
|
||
|
||
// 尝试用过期旧值 100 更新(应失败)
|
||
if !vv.CAS(100, 300) {
|
||
fmt.Println("✅ 检测到非法修改:CAS 拒绝使用过期旧值更新")
|
||
}
|
||
|
||
// 使用当前正确值更新
|
||
if vv.CAS(200, 300) {
|
||
fmt.Printf("✅ 安全更新成功 | 当前值: %d\n", vv.Load())
|
||
}
|
||
}
|