Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are increment operators in Go atomic on x86?

Here's some background:
I need a counter variable shared between go routines, used for something like a leaky-bucket. I know there's an example of leaky-bucket in Effective Go, concurrent section, but the number that I need to track may be very large, and I feel it's inefficient to use number of elements in a channel to track it. So I am considering of using a shared variable between different routines to track the number.

I understand that without explicit configuration, all go routines are mapped onto one thread. But if I assign more than one thread to the program on a multi-core computer, is increment operators atomic? Is it all the same for different data types (int32, float32, etc.) on different machines (x86_32, x86_64, arm)?

To be more concrete, What if I have counter += 1000 in one routine, and counter -= 512 in another routine, and the two routines happens to be running in two threads? Do I need to worry about thread-safty? Shall I put on locks on the counter?

like image 905
Song Gao Avatar asked Dec 17 '12 04:12

Song Gao


People also ask

Is increment operation an atomic?

The increment-memory machine instruction on an X86 is atomic only if you use it with a LOCK prefix. x++ in C and C++ doesn't have atomic behavior.

Does Go have increment operator?

Golang Increment Operator takes a single operand (a number) and increments it by one. Golang Increment Operator applies to integers, floats, and complex values.

Is ++ an operation atomic?

On objects without an atomic type, standard never defines ++ as an atomic operation. C11 defines atomic types in stdatomic. h. If you have an object with an atomic type, a postfix and prefix operators ++ will define an atomic operation as: read-modify-write operation with memory_order_seq_cst memory order semantics.


1 Answers

No, increment should never be assumed to be atomic. Use the atomic addition functions or a mutex.

Lets assume:

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

One goroutine could do atomic.AddInt32(counter, 1000) while another did atomic.AddInt32(counter, -512) without a mutex.

If you would rather use a mutex:

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

func Add(x int32) {
    mutex.Lock()
    defer mutex.Unlock()
    counter += x
}
like image 185
Stephen Weinberg Avatar answered Sep 28 '22 00:09

Stephen Weinberg