* Carl Mastrangelo <
carl.mas...@gmail.com> [171119 19:25]:
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