diff options
author | Russ Cox <rsc@golang.org> | 2019-06-29 09:26:19 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2019-07-01 14:45:49 +0000 |
commit | bc593eac2dc63d979a575eccb16c7369a5ff81e0 (patch) | |
tree | 5f2ee4388576493130dc36ed7cc6cf2cc771ef97 /src/sync | |
parent | c485e8b55918b3b37e6eab47036ab6f16fec226d (diff) | |
download | go-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.go | 14 |
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) |