Why supporting atomic.Load and atomic.Store in Go?

huangapple go评论82阅读模式
英文:

Why supporting atomic.Load and atomic.Store in Go?

问题

我认为atomic.Load(addr)应该等于*addratomic.Store(addr, newval)应该等于*addr = newval。那么为什么使用*addr*addr = newval不是原子操作呢?我的意思是它们最终会被解释为只有一条CPU指令(即原子操作)吧?

英文:

I think atomic.Load(addr) should equal *addr and atomic.Store(addr, newval) should equal *addr = newval. So why doing so(using *addr or *addr = newval) is not a atomic operation? I mean they will eventually be interpreted to be just one cpu instruction(which is atomic)?

答案1

得分: 5

由于排序保证和内存操作的可见性。例如:

y:=0
x:=0
x=1
y=1

在上面的程序中,另一个goroutine可以看到x和y的值为(0,0)、(0,1)、(1,0)或(1,1)。这是因为编译器重新排序代码、编译器优化或硬件级别的内存操作重新排序。然而:

y:=0
x:=0
x:=1
atomic.StoreInt64(&y,1)

如果另一个goroutine看到atomic.LoadInt64(&y)==1,那么这个goroutine可以保证看到x=1。

另一个例子是忙等待。下面的例子来自Go内存模型:

var a string
var done bool

func setup() {
	a = "hello, world"
	done = true
}

func main() {
	go setup()
	for !done {
	}
	print(a)
}

这个程序不能保证终止,因为main函数中的for循环不能保证看到done=true的赋值。程序可能无限运行,可能打印空字符串,也可能打印"hello, world"。

done=true替换为原子存储,并将for循环中的检查替换为原子加载,可以保证程序始终完成并打印"hello, world"。

关于这些内容的权威文档是Go内存模型:

https://go.dev/ref/mem

英文:

Because of ordering guarantees, and memory operation visibility. For instance:

y:=0
x:=0
x=1
y=1

In the above program, another goroutine can see (0,0), (0,1), (1,0), or (1,1) for x and y. This is because of compiler reordering the code, compiler optimization,s or because of memory operation reordering at the hardware level. However:

y:=0
x:=0
x:=1
atomic.StoreInt64(&y,1)

If another goroutine sees atomic.LoadInt64(&y)==1, then the goroutine is guaranteed to see x=1.

Another example is the busy-waiting. The following example is from the go memory model:

var a string
var done bool

func setup() {
	a = "hello, world"
	done = true
}

func main() {
	go setup()
	for !done {
	}
	print(a)
}

This program is not guaranteed to terminate, because the for-loop in main is not guaranteed to see the done=true assignment. The program may run indefinitely, may print empty string, or it may print "hello, world".

Replacing done=true with an atomic store, and the check in the for-loop with an atomic load guarantees that the program always finishes and prints "hello, world".

The authoritative document about these is the go memory model:

https://go.dev/ref/mem

huangapple
  • 本文由 发表于 2023年1月31日 11:29:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/75292441.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定