假设我有以下函数 doWork
,它在 goroutine 中开始一些工作并返回一个 Result
来检查完成和错误:
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
}
其中 Result
是以下结构:
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
}
如果我在关闭 doneCh
之前设置 err
,这段代码线程安全吗:
defer func() {
r.err = err
close(r.doneCh)
}()
或者编译器是否可以随意订购 r.err = err
和 close(r.doneCh)
指令,在这种情况下我需要一个互斥锁以防止并发读/写错误。
最佳答案
只有当您的注释被遵守并且 Err()
直到从 Done()
读取返回时才被调用,它才是线程安全的。
您可以通过将其重新实现为简单地使 Err()
阻塞:
func (r *Result) Err() error {
<-r.doneCh
return r.err
}
这将保证 Err()
仅在 done 完成后返回。鉴于 err 在工作出错之前将为零,您无法判断 Err()
是否成功返回是因为工作已完成还是因为它尚未完成或出错,除非您阻止 Done()
首先,在这种情况下,为什么不让 Err()
阻塞呢?
关于multithreading - 这个 Go 代码是线程安全的还是我需要一个互斥体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49349527/