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

111 lines
2.4 KiB
Markdown

# 同步原语模式
互斥锁和原子操作的详细模式 —— 涵盖互斥锁嵌入陷阱和类型安全的原子访问。
---
## 不要嵌入互斥锁
如果你通过指针使用结构体,互斥锁应该是非指针字段。不要在结构体中嵌入互斥锁,即使该结构体未被导出。
```go
// 不好:嵌入的互斥锁将 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]
}
```
```go
// 好:命名字段使互斥锁保持为实现细节
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` 等),容易忘记一致地使用原子操作。
```go
// 不好:容易忘记原子操作
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
}
```
```go
// 好:类型安全的原子操作
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](https://pkg.go.dev/go.uber.org/atomic))通过隐藏底层类型来增加类型安全性。
---
## Channel 方向示例
指定方向可以防止意外误用:
```go
// 好:指定方向 - 清晰的所有权
func sum(values <-chan int) int {
total := 0
for v := range values {
total += v
}
return total
}
```
```go
// 不好:未指定方向 - 允许意外误用
func sum(values chan int) (out int) {
for v := range values {
out += v
}
close(values) // 漏洞!这能通过编译但不应该发生。
}
```