multithreading - 这个 Go 代码是线程安全的还是我需要一个互斥体?

标签 multithreading go mutex race-condition

假设我有以下函数 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 = errclose(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/

相关文章:

go - sort.Search,寻找一个不在 slice 中的数

api - slice ,groupBy []数组

go - 如何从mapset.Set 中制作 slice ?

c# - ReleaseMutex 在单线程 C# Windows 窗体应用程序中失败

swift - 在OperationQueue中打印1到10不打印整数

java - java中的可重入锁

c++ - 如何让协程始终在同一个线程中工作?

c - 如何通过在本地使用互斥变量来锁定线程?

c++ - 在 C++ 中接受基于线程表现不同的套接字包括

c# - 从 C# 线程调用非托管代码