在 go 中推迟互斥锁解锁时是否会发生数据竞争?

sbs*_*sbs 4 mutex go deferred

这个 Get 方法有问题并且容易出现理论数据竞赛吗?

type item struct {
    val   int
    mutex sync.RWMutex
}

func (i *item) Set(val int) {
    i.mutex.Lock()
    defer i.mutex.Unlock()
    i.val = val
}

func (i *item) Get() int {
    i.mutex.RLock()
    defer i.mutex.RUnlock()
    return i.val
}
Run Code Online (Sandbox Code Playgroud)

我问是因为我在-race使用以前的代码运行测试时看到了罕见的数据竞争,但找不到任何复制效果的方法。

在延迟执行 RUnlock 和我们从结构中读取和返回值之间,是否可以将 i.val 设置为不同的值?

Get() 必须是这样的吗?:

func (i *item) Get() int {
    i.mutex.RLock()
    defer i.mutex.RUnlock()
    val := i.val
    return val
}
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 6

您的代码是安全的,在return评估语句的表达式列表后执行延迟函数。如果您将命名结果参数,返回值也将在调用延迟函数之前分配给它们(您甚至可以在从封闭函数“真正”返回之前修改返回值)。

无需创建局部变量来存储i.val.