]> Cypherpunks repositories - gostls13.git/commitdiff
sync: document implementation of Once.Do
authorRuss Cox <rsc@golang.org>
Sat, 29 Jun 2019 13:26:19 +0000 (09:26 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 1 Jul 2019 14:45:49 +0000 (14:45 +0000)
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>
src/sync/once.go

index 84761970dd87df766951e58f1915842c2f2c14b8..ca044082241232ec7ed7fe2a850a9e10d0978633 100644 (file)
@@ -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)