Suppose I have the following function, doWork, that starts some work in a goroutine and returns a Result to check for completion and error:
func doWork() *Result {
r := Result{doneCh: make(chan struct{})}
go func() {
var err error
defer func() {
r.err = err
close(r.doneCh)
}()
// do some work
}()
return &r
}
where Result is the following struct:
type Result struct {
doneCh chan struct{}
err error
}
// doneCh returns a closed chan when the work is done.
func (r *Result) Done() <-chan struct{} {
return r.doneCh
}
// Err returns a non-nil err if the work failed.
// Don't call Err until Done returns a closed chan.
func (r *Result) Err() error {
return r.err
}
is this code thread safe if I set err before closing doneCh:
defer func() {
r.err = err
close(r.doneCh)
}()
or is the compiler free to order the r.err = err and close(r.doneCh) instructions as it likes, in which case I'd need a mutex to prevent concurrent read/writes on error.