避免锁定并发C代码的一个看似聪明的技巧是这样的:我有一个全局变量ptr
指向mystruct
,我想更新该结构。因此,我将分配一个新的mystruct
,填充中的数据,然后才会通过将ptr
指向该世界,我可以将更改显示给全世界新的mystruct
对象。
这是不正确的,因为它取决于写入的顺序,并且不能保证在对新ptr
的所有存储都采取后,对mystruct
的写入将对其他线程可见地点。因此,可以返回部分初始化的新mystruct
对象。
我的问题是:这也可以在Go中发生吗?我认为可以,但我不得不说我发现The Go Memory Model有点难以理解。
我写了一些Go代码来测试它,但在我的机器上,坏的行为并没有表现出来:
package main
import (
"fmt"
"time"
)
type mystruct struct {
a int
b int
}
var (
ptr *mystruct
counter int
)
func writer() {
for {
counter += 1
s := mystruct{a: counter, b: counter}
ptr = &s
}
}
func reader() {
time.Sleep(time.Millisecond)
for {
if ptr.a != ptr.b {
fmt.Println("Oh no, I'm so buggy!")
}
}
}
func main() {
go writer()
go reader()
select {}
}
这当然没有任何证据。
请您简单比较一下Go的goroutines提供的内存保证与C中POSIX线程提供的(几乎没有保证)?
答案 0 :(得分:2)
2014年5月31日的版本
建议
如果您必须阅读本文档的其余部分以了解该行为 你的计划,你太聪明了。
不要聪明。
我[大卫]写了一些Go代码来测试它。
你的Go程序有数据竞赛。结果未定义。
$ go run -race david.go
==================
WARNING: DATA RACE
Read at 0x000000596cc0 by goroutine 7:
main.reader()
/home/peter/gopath/src/david.go:29 +0x4b
Previous write at 0x000000596cc0 by goroutine 6:
main.writer()
/home/peter/gopath/src/david.go:22 +0xf8
Goroutine 7 (running) created at:
main.main()
/home/peter/gopath/src/david.go:37 +0x5a
Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/david.go:36 +0x42
==================
==================
WARNING: DATA RACE
Read at 0x00c0000cc270 by goroutine 7:
main.reader()
/home/peter/gopath/src/david.go:29 +0x5b
Previous write at 0x00c0000cc270 by goroutine 6:
main.writer()
/home/peter/gopath/src/david.go:21 +0xd2
Goroutine 7 (running) created at:
main.main()
/home/peter/gopath/src/david.go:37 +0x5a
Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/david.go:36 +0x42
==================
==================
WARNING: DATA RACE
Read at 0x00c0000cda38 by goroutine 7:
main.reader()
/home/peter/gopath/src/david.go:29 +0x7f
Previous write at 0x00c0000cda38 by goroutine 6:
main.writer()
/home/peter/gopath/src/david.go:21 +0xd2
Goroutine 7 (running) created at:
main.main()
/home/peter/gopath/src/david.go:37 +0x5a
Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/david.go:36 +0x42
==================
<<SNIP>>
你的Go计划:david.go
:
package main
import (
"fmt"
"time"
)
type mystruct struct {
a int
b int
}
var (
ptr *mystruct
counter int
)
func writer() {
for {
counter += 1
s := mystruct{a: counter, b: counter}
ptr = &s
}
}
func reader() {
time.Sleep(time.Millisecond)
for {
if ptr.a != ptr.b {
fmt.Println("Oh no, I'm so buggy!")
}
}
}
func main() {
go writer()
go reader()
select {}
}