------- 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

Reply via email to