The closest standard points to this 17.6.5.8 [reentrancy] :
1 - Except as otherwise explicitly specified in this standard, it is defined by an implementation whose functions in the C ++ standard library can be recursively returned.
Unfortunately, the call_once specification call_once not say whether it is recursive (or cross-draw recursive), and the preamble of the thread support library does not say anything about this either.
Nevertheless, the implementation of VC ++ is clearly suboptimal, especially since you can write a version of userland call_once using condition_variable :
#include <mutex> #include <condition_variable> struct once_flag { enum { INIT, RUNNING, DONE } state = INIT; std::mutex mut; std::condition_variable cv; }; template<typename Callable, typename... Args> void call_once(once_flag &flag, Callable &&f, Args &&...args) { { std::unique_lock<std::mutex> lock(flag.mut); while (flag.state == flag.RUNNING) { flag.cv.wait(lock); } if (flag.state == flag.DONE) { return; } flag.state = flag.RUNNING; } try { f(args...); { std::unique_lock<std::mutex> lock(flag.mut); flag.state = flag.DONE; } flag.cv.notify_all(); } catch (...) { { std::unique_lock<std::mutex> lock(flag.mut); flag.state = flag.INIT; } flag.cv.notify_one(); throw; } }
Note that this is a small-scale implementation; you can also write a coarse-grained implementation that uses one pair of mutex and a condition variable for all flags, but then you need to make sure that you notify all waiting threads when throwing exceptions (for example, libC ++ does this).
For efficiency, you can make once_flag::state atomic and use a double-check lock; this is omitted here for brevity.
source share