尚不存在的对象的竞争条件

Ale*_*xey 0 go race-condition

我的比赛状况很奇怪。问题是它发生在尚不存在的对象内部。

这是一个演示代码:

package main

import (
    //"fmt"
    "time"
)

type Object1 struct {
    A int
    B string
    C []int
    D *Object2
}

type Object2 struct {
    A int
}

func NewObject1() *Object1 {
    return &Object1{
        A: 1,
        B: "abc",
        C: []int{0, 1},
        D: &Object2{},
    }
}

func main() {
    list := []*Object1{}

    tempA := 0
    tempB := ""
    tempC := []int{}
    tempD := &Object2{}

    go func() {
        for {
            for _, object := range list {
                tempA = object.A
                tempB = object.B
                tempC = object.C
                tempD = object.D
            }
        }
    }()

    for {
        list = append(list, NewObject1())

        //fmt.Println("list", list)
        time.Sleep(1 * time.Second)
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我用-race标志运行它-我得到警告:

WARNING: DATA RACE
Read at 0x00c000094040 by goroutine 5:
  main.main.func1()
      /tmp/race.go:39 +0x84

Previous write at 0x00c000094040 by main goroutine:
  main.main()
      /tmp/race.go:21 +0x2a9

Goroutine 5 (running) created at:
  main.main()
      /tmp/race.go:36 +0x276
==================
==================
WARNING: DATA RACE
Read at 0x00c000094048 by goroutine 5:
  main.main.func1()
      /tmp/race.go:40 +0xbe

Previous write at 0x00c000094048 by main goroutine:
  main.main()
      /tmp/race.go:22 +0x2ca

Goroutine 5 (running) created at:
  main.main()
      /tmp/race.go:36 +0x276
==================
==================
WARNING: DATA RACE
Read at 0x00c000094058 by goroutine 5:
  main.main.func1()
      /tmp/race.go:41 +0x118

Previous write at 0x00c000094058 by main goroutine:
  main.main()
      /tmp/race.go:23 +0x341

Goroutine 5 (running) created at:
  main.main()
      /tmp/race.go:36 +0x276
==================
==================
WARNING: DATA RACE
Read at 0x00c000094070 by goroutine 5:
  main.main.func1()
      /tmp/race.go:42 +0x180

Previous write at 0x00c000094070 by main goroutine:
  main.main()
      /tmp/race.go:24 +0x3b8

Goroutine 5 (running) created at:
  main.main()
      /tmp/race.go:36 +0x276
==================
Run Code Online (Sandbox Code Playgroud)

但是那怎么可能呢?在goroutine内进行读取,在NewObject1()。每个Object1字段4个错误。NewObject1()尚未创建将其追加到list切片的对象。因此list在阅读过程中应为空或充满正常完成的物体。

我心目中的分步工作流程:

  1. 列表为空;
  2. 你开始创造新的object1;
  3. 清单仍然为空;
  4. 您创建了一个新对象,然后将其添加到列表中;
  5. 仅现在list有1个元素;
  6. 阅读发生。

我在这里看不到比赛状况。如果您有不同的看法-请显示您自己的工作流程。

zer*_*kms 5

竞争检测器检测到您同时在内存中读写相同的地址。

根据定义,这是一场数据竞赛。

何时将数据实际放置到该地址(以及是否完全放置在该地址)都没有关系。唯一重要的是,您可以在不同步的情况下在不同的goroutine中访问相同的内存,而这些操作之一就是“写”操作。

两者都不是关于Go的,而是优质的资源:

  1. https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/-该博客中的所有其他文章(基本上)都是瑰宝。
  2. http://deadlockempire.github.io/-类似拼图的游戏,揭示了同步和并发问题的细微差别

  • @Alexey问题是,如果启动2个goroutine,一个将创建一个值(并将其存储在变量中),另一个则睡眠1小时并尝试从变量中读取该值,而没有同步,则无法保证创建会发生在阅读之前。goroutine调度程序将尽力而为,但只有同步才能保证,否则“无所不能”。 (2认同)