2017-02-14 20 views
4

Я знаю, что может случиться так, что g печатает 2, а затем 0, учитывая следующий код.Выполняют ли атомарные операции в голанге связь между событиями?

var a, b uint32 

func f() { 
    a = 1 
    b = 2 
} 

func g() { 
    fmt.Println(b) 
    fmt.Println(a) 
} 

func main() { 
    go f() 
    g() 
} 

Что делать, если я изменяю все операции чтения и записи на атомные операции? Гарантируется ли это, что если g сначала печатает 2, тогда также печатается 1?

var a, b uint32 

func f() { 
    atomic.StoreUint32(&a, 1) 
    atomic.StoreUint32(&b, 2) 
} 

func g() { 
    fmt.Println(atomic.LoadUint32(&b)) 
    fmt.Println(atomic.LoadUint32(&a)) 
} 

func main() { 
    go f() 
    g() 
} 
+0

Вы попробовали? В большинстве случаев 'f()' не будет выполняться вообще. – JimB

ответ

2

Нет. Синхронизация отсутствует, поэтому нет связи "happens before".

Synchronization между goroutines осуществляется через канал связи и блокировки операций.

Ключевой пункт в модели памяти является:

В одном goroutine, читают и пишут, должны вести себя так, как будто они выполняются в порядке, указанном в программе. То есть, компиляторы и процессоры могут изменять порядок чтения и записи, выполненных в одном канате, только если переупорядочение не изменяет поведение внутри этого goroutine, как определено спецификацией языка. Из-за этого переупорядочения порядок исполнения, наблюдаемый одной горутой, может отличаться от порядка, воспринимаемого другим. Например, если один goroutine выполняет a = 1; b = 2 ;, другой может наблюдать обновленное значение b перед обновленным значением a.

+0

исправьте меня, если я ошибаюсь: предположим ev1 как a = 1, ev2 как b = 2, ev3 как print a, ev4 as print b. Поскольку синхронизация не может произойти, что ev3 и ev4 выполняются до ev1 & ev2. Но если ev3 print 2 это означает также, что ev1 и ev2 уже выполнены, поэтому ev4 будет точно печатать 1. Я не прав? – Tinwor

+2

@Tinwor: Нет, это не гарантируется, особенно без атомных операций. Каждый goroutine может находиться в другом потоке, на другом ядре, на другом узле NUMA и просматривать другую память. Даже при использовании атомных операций неявный порядок операций технически применим только в goroutine, поэтому я не думаю, что это будет гарантировано моделью памяти. – JimB

2

Практически он будет работать так, как вы описали. Компилятор Go не будет переупорядочивать атомные операции, а атомный магазин реализуется с использованием XCHG на amd64 (и аналогичных инструкциях на других архитектурах): https://github.com/golang/go/blob/release-branch.go1.8/src/cmd/compile/internal/ssa/gen/AMD64.rules#L472

Это поведение не указано на данный момент (начиная с Go 1.8) и может изменение, см. обсуждение на https://github.com/golang/go/issues/5045 для получения дополнительной информации.