A seemingly clever trick to avoid locking in concurrent C code goes like this: I have a global variable ptr which points to a mystruct and I want to update that structure. So I'll allocate a new mystruct, fill the data in and only then I'll make the change visible to the world by pointing ptr to the new mystruct object.
This is incorrect as it depends on the ordering of writes and there's no guarantee that the write to ptr will become visible to other threads after all stores to the new mystruct have taken place. Therefore, the new mystruct object can be returned partially initialized.
My question is: can this happen in Go, too? I think it can, but I have to say I found The Go Memory Model a little incomprehensible.
I wrote a bit of Go code to test it out, but on my machine, the bad behavirour does not manifest itself:
package main
import (
"fmt"
"time"
)
type mystruct struct {
a int
b int
}
var (
ptr *mystruct
counter int
)
func writer() {
for {
counter += 1
s := mystruct{a: counter, b: counter}
ptr = &s
}
}
func reader() {
time.Sleep(time.Millisecond)
for {
if ptr.a != ptr.b {
fmt.Println("Oh no, I'm so buggy!")
}
}
}
func main() {
go writer()
go reader()
select {}
}
This of course proves nothing.
Can you please provide a very brief comparison of memory guarantees provided by Go's goroutines with (almost no guarantees) provided by a POSIX thread in C?