------- Additional Comments From qrczak at knm dot org dot pl 2005-02-20 21:43 ------- > >Static locals in C++ are an equivalent to pthread_once in C/POSIX. > > Even in the single-threaded case, C++ leaves it undefined what happens if you > reenter a function that invokes a static initializer from that static > initializer. To argue that this means it should be defined for the > multi-threaded case is absurd.
There is a fundamental difference between the second access made from the same or from a different thread. Access from the same thread means that there is a contradiction in the program: the data depends on itself. This is always a bug. The implementation may be helpful and detect this (gcc4 throws exception recursive_init), but in general undefined behavior is consistent with the philosophy of C/C++. The same applies to recursive pthread_once and to a recursive mutex (except that with mutexes you have an option to allow recursive locking). Access from a different thread most often means that the timing was unfortunate and two threads happened to try to perform initialization on first use almost simultaneously, closer in time than the time needed for the initialization. While there is a remote possibility that the threads were not independent, the second thread was a worker spawned by the first one, the first one will wait for the second one to finish its work, the second one will wait for the first one to complete the initialization, and we will have a deadlock - almost always this is not the case, this is just unfortunate timing, and the first thread will complete initialization while the second one is waiting. It makes no sense to optimize for the case of a bug which causes undefined behavior, so the language assumes that there is no bug and arranges the program to run according to the obvious intended semantics of independent threads simultaneously accessing a lazily initialized variable: the second thread waits for the first to complete the initialization, as if it got there some time later. The same applies to pthread_once and to a mutex. Obviously the C++ standard sees only the first scenario, a single thread, so it just declares reentering a static local initializer invalid. But there is no conceptual problem with "reentering" the initializer from a different thread - it just have to wait until the first one finishes. A hypothetical multithreaded C++ should state this as the semantics of static locals. Look at the semantics of Glasgow Haskell which combines lazy evaluation with threads. When the given lazy variable is reentered, if this is the same thread which started computing its value, we have a cyclic dependency and the runtime detects this as an error; and if this is a different thread, the second thread waits for the first one to complete computing the value, because almost always this is just an unfortunate timing and this is the obvious way to resolve it. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20099