In https://golang.org/ref/mem#tmp_10, this program is not safe as below, there is no guarantee to print the newest msg
type T struct {
msg string
}
var g *T
func setup() {
t := new(T)
t.msg = "hello, world"
g = t
}
func main() {
go setup()
for g == nil {
}
print(g.msg)
}
In JAVA, its ok for volatile g, we have to use rwmutex to keep printing the newest msg in golang as below?
type T struct {
msg string
rwlock sync.RWMutex
}
var g = &T{}
func setup() {
g.rwlock.Lock()
defer g.rwlock.Unlock()
g.msg = "hello, world"
}
func main() {
go setup()
printMsg()
}
func printMsg() {
g.rwlock.RLock()
defer g.rwlock.RUnlock()
print(g.msg)
}
I think it is better if you use channel.
type T struct {
msg string
doneC chan struct{}
}
func NewT() *T {
return &T{
doneC: make(chan struct{}, 1),
}
}
func (t *T) setup() {
t.msg = "hello, world"
t.doneC <- struct{}{}
}
func main() {
t := NewT()
go t.setup()
<- t.doneC // or use select to set a timeout
fmt.Println(t.msg)
}
Here are some other options.
Busy wait. This program completes in the current version of of Go, but the spec does not guarantee it. Run it on the playground.
package main
import (
"runtime"
"sync/atomic"
"unsafe"
)
type T struct {
msg string
}
var g unsafe.Pointer
func setup() {
t := new(T)
t.msg = "hello, world"
atomic.StorePointer(&g, unsafe.Pointer(t))
}
func main() {
go setup()
var t *T
for {
runtime.Gosched()
t = (*T)(atomic.LoadPointer(&g))
if t != nil {
break
}
}
print(t.msg)
}
Channel. Run it on the playground.
func setup(ch chan struct{}) {
t := new(T)
t.msg = "hello, world"
g = t
close(ch) // signal that the value is set
}
func main() {
var ch = make(chan struct{})
go setup(ch)
<-ch // wait for the value to be set.
print(g.msg)
}
WaitGroup. Run it on the playground.
var g *T
func setup(wg *sync.WaitGroup) {
t := new(T)
t.msg = "hello, world"
g = t
wg.Done()
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
go setup(&wg)
wg.Wait()
print(g.msg)
}