From: Russ Cox Date: Sat, 29 Jun 2019 13:26:19 +0000 (-0400) Subject: sync: document implementation of Once.Do X-Git-Tag: go1.13rc1~134 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=bc593eac2dc63d979a575eccb16c7369a5ff81e0;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: Rob Pike Reviewed-by: Ingo Oeser --- 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)