首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么不读取/写入其内容的结构的方法仍然会导致争用情况?

为什么不读取/写入其内容的结构的方法仍然会导致争用情况?
EN

Stack Overflow用户
提问于 2016-08-19 14:54:16
回答 1查看 124关注 0票数 6

戴夫切尼博客中,下面的代码显然会导致一种只通过将func (RPC) version() int更改为func (*RPC) version() int就可以解决的争用情况:

代码语言:javascript
复制
package main

import (
        "fmt"
        "time"
)

type RPC struct {
        result int
        done   chan struct{}
}

func (rpc *RPC) compute() {
        time.Sleep(time.Second) // strenuous computation intensifies
        rpc.result = 42
        close(rpc.done)
}

func (RPC) version() int {
        return 1 // never going to need to change this
}

func main() {
        rpc := &RPC{done: make(chan struct{})}

        go rpc.compute()         // kick off computation in the background
        version := rpc.version() // grab some other information while we're waiting
        <-rpc.done               // wait for computation to finish
        result := rpc.result

        fmt.Printf("RPC computation complete, result: %d, version: %d\n", result, version)
}

在看了几次代码之后,我很难相信这段代码有一个竞赛用例。然而,当使用--race运行时,它声称在rpc.result=42上有一个写,在version := rpc.version()上有一个先前的读。我理解写,因为rpc.result的值会发生变化,但是读又会怎样呢?在version()方法中,读取在哪里发生?它不触及rpc的任何值,只返回1。

我想了解以下几点:

1)为什么这个特定的行被认为是对rpc结构的读取?

2)为什么要将RPC改为*RPC来解决种族问题?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-08-19 15:05:59

当您有一个具有如下值接收者的方法时:

代码语言:javascript
复制
func (RPC) version() int {
    return 1 // never going to need to change this
}

你把这个方法叫做:

代码语言:javascript
复制
version := rpc.version() // grab some other information while we're waiting

必须从值rpc中复制一个副本,该值将传递给方法(用作接收方值)。

因此,当一个goroutine go rpc.compute()正在运行并正在修改rpc结构值(rpc.result = 42)时,主goroutine正在复制整个rpc结构值。那里!这是场比赛。

将接收方类型修改为指针时:

代码语言:javascript
复制
func (*RPC) version() int {
    return 1 // never going to need to change this
}

你把这个方法叫做:

代码语言:javascript
复制
version := rpc.version() // grab some other information while we're waiting

这是一个缩写

代码语言:javascript
复制
version := (&rpc).version()

这将rpc值的地址传递给RPC.version(),它只使用指针作为接收方,因此不会复制rpc结构值。而且,由于在RPC.version()中没有使用/读取结构中的任何内容,所以不存在竞争。

注:

请注意,如果RPC.version()将读取RPC.result字段,它也将是一个竞赛,因为一个goroutine修改它,而主goroutine将读取它:

代码语言:javascript
复制
func (rpc *RPC) version() int {
    return rpc.result // RACE!
}

注2:

还请注意,如果RPC.version()将读取未在RPC.compute()中修改的另一个RPC字段,则这将不是一个竞赛,例如:

代码语言:javascript
复制
type RPC struct {
    result int
    done   chan struct{}
    dummy  int
}

func (rpc *RPC) version() int {
    return rpc.dummy // Not a race
}
票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39042074

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档