Files
OpenFlare/.agents/skills/go-concurrency/references/SYNC-PRIMITIVES.md
T
2026-08-04 11:40:32 +08:00

2.4 KiB

同步原语模式

互斥锁和原子操作的详细模式 —— 涵盖互斥锁嵌入陷阱和类型安全的原子访问。


不要嵌入互斥锁

如果你通过指针使用结构体,互斥锁应该是非指针字段。不要在结构体中嵌入互斥锁,即使该结构体未被导出。

// 不好:嵌入的互斥锁将 Lock/Unlock 暴露为 API 的一部分
type SMap struct {
    sync.Mutex // Lock() 和 Unlock() 成为 SMap 的方法
    data map[string]string
}

func (m *SMap) Get(k string) string {
    m.Lock()
    defer m.Unlock()
    return m.data[k]
}
// 好:命名字段使互斥锁保持为实现细节
type SMap struct {
    mu   sync.Mutex
    data map[string]string
}

func (m *SMap) Get(k string) string {
    m.mu.Lock()
    defer m.mu.Unlock()
    return m.data[k]
}

在不好的示例中,Lock 和 Unlock 方法无意中成为了导出 API 的一部分。在好的示例中,互斥锁是对调用方隐藏的实现细节。


原子操作:完整示例

标准 sync/atomic 包操作原始类型(int32、int64 等),容易忘记一致地使用原子操作。

// 不好:容易忘记原子操作
type foo struct {
    running int32 // 原子操作
}

func (f *foo) start() {
    if atomic.SwapInt32(&f.running, 1) == 1 {
        return // 已在运行
    }
    // 启动 Foo
}

func (f *foo) isRunning() bool {
    return f.running == 1 // 竞争!忘记使用 atomic.LoadInt32
}
// 好:类型安全的原子操作
type foo struct {
    running atomic.Bool
}

func (f *foo) start() {
    if f.running.Swap(true) {
        return // 已在运行
    }
    // 启动 Foo
}

func (f *foo) isRunning() bool {
    return f.running.Load() // 不可能意外地非原子读取
}

atomic.Bool、atomic.Int64 等类型(Go 1.19 起在标准库 sync/atomic 中可用,或通过 go.uber.org/atomic)通过隐藏底层类型来增加类型安全性。


Channel 方向示例

指定方向可以防止意外误用:

// 好:指定方向 - 清晰的所有权
func sum(values <-chan int) int {
    total := 0
    for v := range values {
        total += v
    }
    return total
}
// 不好:未指定方向 - 允许意外误用
func sum(values chan int) (out int) {
    for v := range values {
        out += v
    }
    close(values) // 漏洞!这能通过编译但不应该发生。
}