譬如一个 int64 两个协程并发修改
那么会出现一个协程 A 修改了前面 32 位,
然后切换到另一个协程 B 把 64 位都修改了,
接着协程 A 继续修改后 32 位....
最终的结果是 B 决定了前面 32 位,A 决定了后面 32 位...数值上既不是 A 的结果,也不是 B 的结果
嗯, golang 里面的协程是自愿让渡的模式, 但是协程依赖的线程,依旧是操作系统的抢占是模式
也就是说有可能出现,一个协程修改某个值,修改到一半,被挂起, 所以是可能的,这样推论是否正确
int64 位应该没可能, 因为汇编里面有对应的 int64 类型的指令, 不过,如果是个 struct 结构...应该有可能出现这个问题
谢谢
1
innoink 2018-11-04 15:57:40 +08:00 via Android
x64 是不会这样的
实际上一个 cacheline 的都是原子 |
2
bigpigeon 2018-11-04 17:26:59 +08:00
写个单元测试就知道了
|
3
mx1700 2018-11-04 17:42:40 +08:00 via Android
这时候就需要锁了
|
4
mritd 2018-11-05 10:04:45 +08:00 via iPhone
Atomic
|
5
reus 2018-12-03 09:24:07 +08:00
要加锁。
|
6
goodwong 2019-05-29 11:42:57 +08:00
struct 会有差异,见代码:
```go func structRaceWrong() { x := struct { A int B int }{1, 1} var wg sync.WaitGroup wg.Add(1) go func() { for i := 0; i < 1000000; i++ { if x.A != x.B { log.Println("A != B", x.A, x.B) } if i < 3 { log.Printf("%p\n", &x) } } wg.Done() }() wg.Add(1) go func() { for i := 0; i < 1000000; i++ { x = struct { A int B int }{x.A + 1, x.B + 1} // <---------- 导致 A、B 可能不一致 } wg.Done() }() wg.Wait() } // 结论:Go 是值拷贝,结构体会出现复制一半就被其它读取了 func structRaceWrong2() { x := struct { A int B int }{1, 1} var wg sync.WaitGroup wg.Add(1) go func() { for i := 0; i < 1000000; i++ { cp := x if cp.A != cp.B { log.Println("A != B", cp.A, cp.B) } if i < 3 { log.Printf("%p\n", &x) } } wg.Done() }() wg.Add(1) go func() { for i := 0; i < 1000000; i++ { cp := x // <---------- 拷贝也不行,可能只拷贝一半 x = struct { A int B int }{cp.A + 1, cp.B + 1} } wg.Done() }() wg.Wait() } // 结论:通过指针读取的数据是完整的,但不一定是最新的。 func structRaceOk() { x := &struct { A int B int }{0, 0} var wg sync.WaitGroup wg.Add(1) go func() { for i := 0; i < 1000000; i++ { cp := x if cp.A != cp.B { // <---------- 通过指针读取的数据是完整的,但不一定是最新的。 log.Fatal("A != B", cp.A, cp.B) // 不会出现 } if i < 10 { // 抽取前 10 条数据检查 log.Printf("%p -> %p\n", &x, x) log.Printf("-A%d - i%d = %d", cp.A, i, cp.A - i) // 不一定是最新的 } if i - cp.A > 1 { log.Printf("A:%d - i:%d = %d \n", cp.A, i, cp.A - i) } } wg.Done() }() wg.Add(1) go func() { for i := 0; i < 1000000; i++ { cp := x x = &struct { A int B int }{cp.A + 1, cp.B + 1} } wg.Done() }() wg.Wait() } ``` |