* Carl Mastrangelo <carl.mastrang...@gmail.com> [171119 19:25]: > I was playing around with a puzzle trying to break the sync package and > found something cool. Can you think of a definition for f that causes > once.Do to execute the argument more than once? > > package main > > import ( > "sync" > ) > > func main() { > var once sync.Once > var f = // ... > > once.Do(f) > } > > HIGHLIGHT BELOW FOR ANSWER > > package main > > import ( > "fmt" > "sync" > ) > > func main() { > var once sync.Once > var f func() > times := 9 > f = func() { > if times == 0 { > return > } > times-- > fmt.Println("Called") > oldonce := once > *&once = sync.Once{} > once.Do(f) > once = oldonce > > } > once.Do(f) > }
The call to «once.Do(f)» inside f is on an explicitly new instance of Once that is completely independent of the original, as well as independent of the other instances of Once in the recursive calls to f. I do not understand why you believe that this shows once.Do invoking its argument more than once. The implementation of Once uses a uint32 and a sync.Mutex. A Mutex is not safe to copy after it has been used (this is explicitly stated in the Mutex documentation), thus Once is not safe to copy after it has been used. This was clear to me, but perhaps this should be added to the sync.Once documentation. You are creating new instances of Once which are copies of other instances both at «oldonce := once» and «once = oldonce». This makes calling once.Do(f) more than once outside of f a violation of the sync.Mutex contract. The correct way to use Once is to pass around a pointer to an instance, which ensures all invocations of Do use the same underlying uint32 and Mutex. I believe, though I haven't proved it to myself, that if multiple go routines use the same instance of Once, but one of the go routines makes a copy of that instance, the copy could start out with its Mutex in a locked state with nothing to unlock it. ...Marvin -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.