为什么在第一次存储之后不能复制 atomic.Value?

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

Why atomic.Value must not be copied after the first Store?

问题

Value提供了对一致类型值的原子加载和存储。Value的零值从Load返回nil。一旦调用了Store,就不能复制Value。

我从atomic.Value的注释中读到了上述内容。它说“在第一次Store之后,Value不能被复制”,但没有说明原因。

为什么在第一次Store之后,atomic.Value不能被复制呢?

英文:

> A Value provides an atomic load and store of a consistently typed value. The zero value for a Value returns nil from Load. Once Store has been called, a Value must not be copied.

I read the above comment from atomic.Value.
It says that "a Value must not be copied", but the reason is not stated.

Why atomic.Value must not be copied after the first Store?

答案1

得分: 1

为什么在第一次存储之后不能复制 atomic.Value?

因为文档是这样说明的。

(内部实现需要这样做。这里没有什么可操作的事情。)

英文:

> Why atomic.Value must not be copied after the first Store?

Because the documentation says so.

(The internal implementation requires this. Nothing to see here, there is no actionable thing about this.)

答案2

得分: 1

除了@Volker的答案和@icza的评论之外,推理很简单:atomic.Value的实现包括用于直接提供类型合约所保证的原子性的“某些东西”——与通常情况下包括对该“东西”的引用或指针不同,因此当将atomic.Value类型的变量复制到另一个变量时,该“东西”也会被复制(克隆)。

现在假设一个实现决定将(通常由内核提供的)信号量互斥锁临界区或其他任何方便的锁定机制包含到atomic.Value类型中。

现在考虑一种争用的情况:一个goroutine尝试在另一个goroutine并行修改该值时读取该值。
写入goroutine通过内部保护机制(无论是如何实现的)“获取”“独占写入权限”,然后您复制该值。
暂且不论这种复制是否创建了经典的数据竞争情况,您现在可以看到复制的结果将是两个atomic.Value类型的变量,每个变量都将被“锁定”以获取独占写入权限。
但是,原始变量仍然处于合理的状态——希望更新变量的goroutine最终会完成并将其“释放”回来,将变量恢复到正常状态,而复制将永远被锁定在“已获取更新”状态中,直到没有goroutine打算执行该更新为止。糟糕!

顺便说一下,由于完全相同的原因,您不能在第一次使用后复制sync.Mutex变量。

英文:

In addition to the answer by @Volker and the comment by @icza, the reasoning is quite simple: the implementation of atomic.Value includes something which is used to provide the atomicity guaranteed by the type's contract, directly — as opposed to including a reference to or, as it usually happens, a pointer to, such thing, and hence when a variable of type atomic.Value is copied to another variable that "thing" is copied, (cloned) too.

Now suppose that an implementation decided to include into the type of atomic.Value a (usually kernel-provided) semaphore or mutex, or critical section or whatever else — any convenient locking mechanism.

Consider now a case of contention: some goroutine tries to read the value while another one tries to modify it, in parallel.
The writing goroutine "acquires" "exclusive write permission" via that internal protection mechanism — however it is implemented — and then you copy the value.
Leaving aside the problem of such copying creating a classical data race case, you can now see that the result of the copy will be two variables of type atomic.Value, and each of them will be "locked" for that exclusive write permission.
But while the original variable remains in a sensible state — the goroutine which wanted to update the variable will eventually be done with that and will "release" its permit back, returning the variable into the normal state, the copy will be forever latched in that "acquired for update" state while there is no goroutine intending to perform that update. Oops!


By the way, you cannot copy sync.Mutex variable after its first use for precisely the same reasons.

huangapple
  • 本文由 发表于 2021年5月21日 15:50:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/67632767.html
匿名

发表评论

匿名网友

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

确定