
I've checked in a new version on trunk
https://svn.boost.org/svn/boost/trunk/boost/thread/win32/once.hpp
This version only allocates an event if there is contention. The event (if there is one) is reset just before invoking the function in the one thread that gets to run it. It is set after the completion flag is set. The event is deallocated when the last thread that is using it exits call_once. If a thread exits because f() threw an exception then this is counted separately in order to avoid prematurely destroying the event. If f() throws every time it is called then the event will stick around until the flag is destroyed.
It's not as tidy as I'd like, but I think the logic is sound.
Probably, except you never actually wait on the event! :-) (or maybe I missed it). I'm assuming you mean to wait on it after the 'waiting' thread creates it if it doesn't exist: if(!counted) { BOOST_INTERLOCKED_INCREMENT(&flag.count); counted=true; status=::boost::detail::interlocked_read_acquire(&flag.status); if(status==function_complete_flag_value) { break; } event_handle=::boost::detail::interlocked_read_acquire(&flag.event_handle); if(!event_handle) { event_handle=::boost::detail::allocate_event_handle(flag.event_handle); continue; } ***** Wait(event_handle); ****** ? } Also, once_flag is no longer a POD (because of the destructor). Not sure if that is important. It is also now approx 4 * sizeof(long) instead of just sizeof(long or pointer). :-( Still looking at the overall algorithm... Tony