Являются ли операторы приращения в атоме Go атомом на x86?
Вот какой фон:
Мне нужна переменная счетчика, разделяемая между режимами go, используемая для чего-то вроде просачивающегося ведра. Я знаю, что есть пример просачивающегося потока в Effective Go, параллельный раздел, но число, которое мне нужно отслеживать, может быть очень большим, и я считаю неэффективным использовать количество элементов в канале для его отслеживания. Поэтому я рассматриваю возможность использования общей переменной между различными процедурами для отслеживания числа.
Я понимаю, что без явной конфигурации все подпрограммы go отображаются в один поток. Но если я назначаю более одного потока для программы на многоядерном компьютере, атомы приращения атома? Все ли одинаково для разных типов данных (int32
, float32
и т.д.) На разных машинах (x86_32
, x86_64
, arm
)?
Чтобы быть более конкретным, что, если у меня есть counter += 1000
в одной подпрограмме и counter -= 512
в другой процедуре, и две подпрограммы работают в двух потоках? Нужно ли беспокоиться о потокобезопасности? Должен ли я надеть блокировки на counter
?
Ответы
Ответ 1
Нет, приращение никогда не следует считать атомарным. Используйте функции добавления атомов или мьютексы.
Предположим, что
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
}