19

这是一些背景知识:
我需要一个在 go 例程之间共享的计数器变量,用于类似漏桶的东西。我知道在 Effective Go,concurrent section 中有一个leaky-bucket 的例子,但是我需要跟踪的数量可能非常大,我觉得使用通道中的元素数量来跟踪它是低效的。所以我正在考虑在不同的例程之间使用共享变量来跟踪数字。

我知道如果没有明确的配置,所有的 goroutine 都会映射到一个线程上。但是如果我在多核计算机上为程序分配多个线程,增量运算符是原子的吗?不同机器( , , )上的不同数据类型(int32,float32等)是否都一样?x86_32x86_64arm

更具体地说,如果我有counter += 1000一个例程和counter -= 512另一个例程,而这两个例程恰好在两个线程中运行,该怎么办?我需要担心线程安全吗?我应该把锁放在上面counter吗?

4

1 回答 1

25

不,增量不应该被认为是原子的。使用原子加法函数或互斥体。

让我们假设:

import "sync/atomic"
var counter = new(int32)

一个 goroutine 可以做atomic.AddInt32(counter, 1000),而另一个没有atomic.AddInt32(counter, -512)互斥体可以做。

如果您更愿意使用互斥锁:

import "sync"
var counter int32
var mutex sync.Mutex

func Add(x int32) {
    mutex.Lock()
    defer mutex.Unlock()
    counter += x
}
于 2012-12-17T05:06:15.933 回答