我们只能使用无挥发性的RWMutex吗?

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)
}