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?