Состояние гонки для еще не существующего объекта - PullRequest
0 голосов
/ 02 апреля 2019

У меня странное состояние гонки. Проблема в том, что это происходит внутри объекта, который еще не существует.

Вот демонстрационный код:

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)
    }
}

Если я запускаю его с флагом -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
==================

Но как это возможно? Чтение происходит внутри goroutine и запись внутри NewObject1(). 4 ошибки для каждого поля Object1. NewObject1() еще не создал объект, чтобы добавить его к срезу list. Так что list во время чтения должен быть пустым или заполняться нормально завершенными объектами.

Шаг за шагом, рабочий процесс в моей голове:

  1. список пуст;
  2. вы начинаете создавать новые object1;
  3. список еще пуст;
  4. вы создали новый объект и только потом добавляете его в список;
  5. только теперь в списке есть 1 элемент;
  6. чтение происходит.

Я не вижу здесь состояния гонки. Если вы думаете иначе - пожалуйста, покажите свой собственный рабочий процесс, как все происходит.

1 Ответ

5 голосов
/ 02 апреля 2019

Детектор гонки обнаруживает, что вы одновременно читаете и записываете один и тот же адрес в памяти.

По определению это гонка данных.

Не имеет значения, когда данные были фактически введены по этому адресу(и был ли он вообще там поставлен).Важно только то, что вы обращаетесь к одной и той же памяти в разных процедурах без синхронизации, и одной из этих операций является «запись».

Обе не относятся к Go, но являются исключительно качественными ресурсами:

  1. https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/ - эта и, в основном, каждая другая статья в этом блоге является жемчужиной.
  2. http://deadlockempire.github.io/ - игра-головоломка, в которой раскрываются нюансы синхронизации и проблем параллелизма
...