并发引用分配可能会出错吗?

时间:2019-06-22 15:52:58

标签: go concurrency thread-safety

我尝试go run -race main.go使用以下代码并获得了WARNING: DATA RACE,但实际上没有发生任何有害的情况。它有什么危害? 在这段代码中,我尝试同时分配引用,从我的角度来看,它应该是原子的,仅在一条指令中即可。

package main

import (
    "context"
    "fmt"
    "sync"
    "time"
)

type my struct {
    value string
}

var global *my

func run(v string, ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()
    t := &my{
        value: v,
    }
l:
    for {
        select {
        case <-ctx.Done():
            break l
        default:
            global = t
        }
    }
}

func main() {
    var a, b int
    for i := 0; i < 100; i++ {
        ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*10)
        wg := sync.WaitGroup{}
        wg.Add(2)
        go run("1", ctx, &wg)
        go run("2", ctx, &wg)
        wg.Wait()
        if  global.value == "1" {
            a++
        } else {
            b++
        }
    }
    fmt.Println(a, b, a + b)
}

go tool objdump -S programm > 1.txt 并在问题线上获得了一些说明

...
            global = t
  0x109a1b7     833da22e100000      CMPL $0x0, runtime.writeBarrier(SB) 
  0x109a1be     750e            JNE 0x109a1ce               
  0x109a1c0     488b442418      MOVQ 0x18(SP), AX           
  0x109a1c5     48890594740e00      MOVQ AX, main.global(SB)        
  0x109a1cc     ebc1            JMP 0x109a18f               
  0x109a1ce     488d3d8b740e00      LEAQ main.global(SB), DI        
  0x109a1d5     488b442418      MOVQ 0x18(SP), AX           
  0x109a1da     e89190fbff      CALL runtime.gcWriteBarrier(SB)     
  0x109a1df     ebae            JMP 0x109a18f
...

已更新:

我了解到,在go语言中,当两个或多个goroutine并发编写引用变量(在此处Is it safe to read a function pointer concurrently without a lock? 中使用)时,这是未定义的行为。但是怎么可能是错误的,那么在汇编中它可能是一条指令(我对吗?)?为什么在语言规范中未将其定义为线程安全的?例如,在Java中,引用分配是线程安全的。

0 个答案:

没有答案