A question about the atomic operations in golang

Is the size of a pointer value 32 bits or 64 bits in golang when build with GOARCH=amd64 option specified and running on 64-bit OS?
If it’s 64-bit size, is a global pointer value 8-byte aligned in memory so that a read or write operation of that pointer value is carried out atomically?
For example, in the following code, is it possible that the global pointer p is only partially updated when the read goroutine read the pointer?

var p *int

void main() {
    i := 1
    p = &i
    go func() { fmt.Println(*p) } ()
}

The scenario I’m concerning is that there is only one write but multiple reads on a global pointer value, and reading of an old value of the pointer is not important. Thanks in advance!

For example, in the following code, is it possible that the global pointer p is only partially updated when the read goroutine read the pointer?

tl;dr; only using sync/atomic works, if you want something to be atomic. And use race detector on your code, it will point out mistakes.

It’s not just about being atomic, it’s also about the compiler knowing that you meant that operation to be atomic. Also it’s been discussed multiple times on forums.

https://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-could-possibly-go-wrong

2 Likes

Hey @ncubrian, as @Egon, has stated, you should be using sync/atomic for atomic operations.

Here is the index of the functions in the sync/atomic package, atomic package - sync/atomic - Go Packages.

P.S. Just for the record, a pointer should only be 8 bits for amd64, not 32 or 64, but you can always check the size of a type or variable by using the unsafe.Sizeof function if it’s ever important to what you’re doing (unsafe package - unsafe - Go Packages).

Edit: As I wrote in my post below, unsafe.Sizeof returns byte size and not bits, so it was actually 64 bits (8 bytes) and forgot that when I wrote the above P.S note :stuck_out_tongue:

Another simple solution for global synchronization is to just use a mutex :stuck_out_tongue:

1 Like

Thanks for your reply, but I don’t quite understand this. Isn’t a pointer type is as large as an int? Since an int is 32 bits, how come a pointer would be 8 bits?

An int is only 8 bits as well on my 64 bit machine:

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	var i int
	fmt.Println(unsafe.Sizeof(i))
}

If you run that on your computer you should see the size of an integer for the system you’re running the code on.

Edit: That’s wrong, I forgot that unsafe.Sizeof returns the size in bytes, not bits, thought I made a mistake, so you are actually right, depending on the size of the int, but in my case you were right that the pointer was actually 64 bits.

If the address is properly aligned, the value will be written to memory atomically

In this code there is no race because the go statement occurs after assignment to p. If that assignment occurred after the go statement, that would be a data race.

Please also read my caution about data races and undefined behaviour in my reply to your question here, Redirecting to Google Groups

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.