Subj : Re: Can C++ local static objects be made thread safe? To : comp.programming.threads From : Gianni Mariani Date : Wed Feb 02 2005 07:22 pm Giancarlo Niccolai wrote: > Gianni Mariani wrote: > > >>David Schwartz wrote: >> >>>"Gianni Mariani" wrote in message >>>news:iaudnW0LQIcam2zcRVn-ig@speakeasy.net... >> >>... > > >>> >>> This isn't quite right. Another thread could see 'm_val' as true, and >>>the 'xlocal' as non-NULL and still not see the writes inside 'x'. You >>>need a memory barrier in every possible case, unfortunately. Not all >>>architectures provide a way for one thread to force another thread to see >>>something. >> >>Just a minute - how can that be. >> >>On the first time through, a memory barrier sync is done. Worst case, >>you can't come out of this code normally without the construction being >>completed. Once you decide that you're locking the mutex, I assume >>barriers are looked after. The m_val value is thread local, meaning >>each thread executed the memory barrier at least once - once the memory >>barrier is synced once, why would it need to be synced again ? If it >>did, somthing much more serious is broken. > > > Please, Gianni, do not take what I am going to say as a personal matter; I'm cool ! > Indeed, I am taking this thread as just an occasion to make a general > statement. > > The fact is that you are trying to solve an unexisting problem. The solution > may be technically clever, and foundamentally right (I don't say it is, > others here more "technical" than I am have argued against it and I am not > commenting their judgment), but the -problem- is incorrect. You are not > looking in the right direction; you are looking DOWN, while you should be > looking BESIDE. Perspective - got it. > > The very heart of threading is not in the clever lock or in the finest > memory barrier; it's in the way you organize your program as a set of > parallel agents. Even if you lock well the initial static-based > constructors (which is a Wrong Thing anyhow, but let's suppose it's fine > for just a moment), this won't solve the general problem of threading > before main. This has nothing to do with threading before main(). In C++, non POD types in static function local scope can be initialized *after* main() is called (and most of them are initialized after main() is called). e.g. #include #include struct A { A() { std::cout << "A"; } }; void foo() { static A a; }; int main() { std::cout << "main"; foo(); foo(); } This prints "mainA" (if the compiler conforms to the standard that is). Not because main() is a magical thing where all works, but > just because main() is the first place where you are in perfect control of > the control flow of the program. And perfect Control of the flow is the > prerequisite for correct parallelism. Sure - no threads *should* run before main(), I can buy that. You HAVE to drop this control now and > then in parallel programs, but YOU are in control about WHEN to drop it and > WHEN to re-acquire it. Loosing this meta-control means just disaster. Still, this has no bearing on the issue of initialization of static function locals. > > So, even if constructors were built right in a MT environment, if they do > depend on each other in a pure parallel fashion, how may a generic program > ever hope to work correctly? Simply because the C++ standard is quite specific in that static function local variables (non POD) must be initialized exactly once on the *first time* that control passes through the variable. All we're doing here is enforcing this requirement. And if there isn't any hope to make the very > generic program using randomly initialized constructors in a MT environment > to work correctly, due NOT to language missing features but to the > impossibility to manage the general parallel flow case, how can ever be > useful a thing allowing you to reach safely such an unsafe state? static local variables is the only mechanism that guarentees order of construction of singletons. Singletons are a very important concept of OO programming. > > A program with parallelism in its static constructor MAY work, and it MAY > take advantage from an automated constructor protection mechanism, but that > would not be the generic case anyhow; it would do only for limited > interaction between parallel agents that cannot be controlled before the > program steps in. As far as I can tell, the solution that GCC has adopted is a clean and very general solution to an otherwise very messy problem. So, how this technique, applied to the generic case, may > ever be useful? For static local variables to work *at all* in an MT environment, somthing like what is described earlier in this thread is required, otherwise your code is broken. .