Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do atomic operations establish a happen-before relation?

I know it can happen that g prints 2 and then 0 given the following code.

var a, b uint32

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

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

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

What if I change all read and write to atomic operations? Is that guaranteed that if g prints 2 first, then 1 is also printed?

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()
}
like image 570
luyi0619 Avatar asked Feb 14 '17 16:02

luyi0619


People also ask

How do you ensure atomic operations?

There are two ways to accomplish an atomic operation: Use a single machine instruction. Tell the operating system in advance not to interrupt the operation.

What does Atomic mean in the context of synchronization )?

In simple words, the atomic means the operation will be either completed or not. The other threads or CPUs won't catch it in the middle of the operation.

Why are atomic operations important?

Atomic operations are important in programs where a shared resource, such as a database, is accessed by multiple threads. An atomic operation is an operation that appears to be instantaneous in the eyes of the other threads. In other words, you cannot catch an atomic operation in the middle.

What is atomic memory access?

An atomic access is a term for a series of accesses to a memory region. Atomic accesses are used by managers when they would like to perform a sequence of accesses to a particular memory region, while being sure that the original data in the region are not corrupted by writes from other managers.


2 Answers

Practically it will work as you described. The Go compiler won't re-order atomic operations and atomic store is implemented using XCHG on amd64 (and similar instructions on other architectures): https://github.com/golang/go/blob/release-branch.go1.8/src/cmd/compile/internal/ssa/gen/AMD64.rules#L472

This behaviour is not specified at the moment (as of Go 1.8) and might change, see discussion at https://github.com/golang/go/issues/5045 for more insights.

like image 105
kostya Avatar answered Oct 04 '22 04:10

kostya


No. There's no synchronization, so there is no "happens before" relationship.

Synchronization between goroutines is done via channel communication and lock operations.

A key paragraph in the memory model is:

Within a single goroutine, reads and writes must behave as if they executed in the order specified by the program. That is, compilers and processors may reorder the reads and writes executed within a single goroutine only when the reordering does not change the behavior within that goroutine as defined by the language specification. Because of this reordering, the execution order observed by one goroutine may differ from the order perceived by another. For example, if one goroutine executes a = 1; b = 2;, another might observe the updated value of b before the updated value of a.

like image 27
JimB Avatar answered Oct 04 '22 03:10

JimB