尚未存在的对象的竞争条件
Race condition for not yet existing object
我有一个奇怪的比赛条件。问题是它发生在一个尚不存在的对象中。
这是一个演示代码:
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()
中。每个 Object1
字段有 4 个错误。 NewObject1()
尚未创建对象以将其附加到 list
切片。所以list
在读取过程中应该是空的或者填充一个正常完成的对象。
我脑海中的一步步工作流程:
- 列表为空;
- 你开始创建新的
object1
;
- 列表还是空的;
- 您创建了一个新对象,然后才将其添加到列表中;
- 现在列表只有 1 个元素;
- 阅读发生了。
我在这里没有看到竞争条件。如果您有不同的想法 - 请展示您自己的工作流程。
争用检测器检测到您同时读取和写入内存中的同一地址。
根据定义,这是一场数据竞赛。
数据实际上何时被放入该地址(以及它是否被放在那里)并不重要。唯一重要的是你在没有同步的情况下访问不同 goroutines 中的相同内存,其中一个操作是 "write".
两者都不是关于 Go 的,但是都是非常优质的资源:
- https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/ - 这篇文章和该博客中的其他文章基本上都是 gem.
- http://deadlockempire.github.io/ - 一款揭示同步和并发问题细微差别的益智类游戏
我有一个奇怪的比赛条件。问题是它发生在一个尚不存在的对象中。
这是一个演示代码:
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()
中。每个 Object1
字段有 4 个错误。 NewObject1()
尚未创建对象以将其附加到 list
切片。所以list
在读取过程中应该是空的或者填充一个正常完成的对象。
我脑海中的一步步工作流程:
- 列表为空;
- 你开始创建新的
object1
; - 列表还是空的;
- 您创建了一个新对象,然后才将其添加到列表中;
- 现在列表只有 1 个元素;
- 阅读发生了。
我在这里没有看到竞争条件。如果您有不同的想法 - 请展示您自己的工作流程。
争用检测器检测到您同时读取和写入内存中的同一地址。
根据定义,这是一场数据竞赛。
数据实际上何时被放入该地址(以及它是否被放在那里)并不重要。唯一重要的是你在没有同步的情况下访问不同 goroutines 中的相同内存,其中一个操作是 "write".
两者都不是关于 Go 的,但是都是非常优质的资源:
- https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/ - 这篇文章和该博客中的其他文章基本上都是 gem.
- http://deadlockempire.github.io/ - 一款揭示同步和并发问题细微差别的益智类游戏