aboutsummaryrefslogtreecommitdiff
path: root/src/sync
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2019-06-29 09:26:19 -0400
committerRuss Cox <rsc@golang.org>2019-07-01 14:45:49 +0000
commitbc593eac2dc63d979a575eccb16c7369a5ff81e0 (patch)
tree5f2ee4388576493130dc36ed7cc6cf2cc771ef97 /src/sync
parentc485e8b55918b3b37e6eab47036ab6f16fec226d (diff)
downloadgo-bc593eac2dc63d979a575eccb16c7369a5ff81e0.tar.gz
go-bc593eac2dc63d979a575eccb16c7369a5ff81e0.zip
sync: document implementation of Once.Do
It's not correct to use atomic.CompareAndSwap to implement Once.Do, and we don't, but why we don't is a question that has come up twice on golang-dev in the past few months. Add a comment to help others with the same question. Change-Id: Ia89ec9715cc5442c6e7f13e57a49c6cfe664d32c Reviewed-on: https://go-review.googlesource.com/c/go/+/184261 Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rob Pike <r@golang.org> Reviewed-by: Ingo Oeser <nightlyone@googlemail.com>
Diffstat (limited to 'src/sync')
-rw-r--r--src/sync/once.go14
1 files changed, 14 insertions, 0 deletions
diff --git a/src/sync/once.go b/src/sync/once.go
index 84761970dd..ca04408224 100644
--- a/src/sync/once.go
+++ b/src/sync/once.go
@@ -38,6 +38,20 @@ type Once struct {
// without calling f.
//
func (o *Once) Do(f func()) {
+ // Note: Here is an incorrect implementation of Do:
+ //
+ // if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
+ // f()
+ // }
+ //
+ // Do guarantees that when it returns, f has finished.
+ // This implementation would not implement that guarantee:
+ // given two simultaneous calls, the winner of the cas would
+ // call f, and the second would return immediately, without
+ // waiting for the first's call to f to complete.
+ // This is why the slow path falls back to a mutex, and why
+ // the atomic.StoreUint32 must be delayed until after f returns.
+
if atomic.LoadUint32(&o.done) == 0 {
// Outlined slow-path to allow inlining of the fast-path.
o.doSlow(f)