Subj : Re: Boost.Threads on its way to C++0x To : comp.programming.threads From : gottlobfrege Date : Wed Apr 27 2005 02:57 am Peter Dimov wrote: > gottlobfrege@gmail.com wrote: > > Peter Dimov wrote: > >> gottlobfrege@gmail.com wrote: > >>> - a static_local template: > >>> > >>> int func() > >>> { > >>> // this thread-safely inits foo only once > >>> static static_local foo(foo_param1, foo_param2,...); > >> > >> How do you solve the race condition WRT the hidden compiler- > > > generated boolean flag? > > > > There are lots of ways, but they all boil down to the same thing: ie > > you ignore the compiler's flag and use your own. And use call_once to > > set your flag. > > Isn't this the usual broken DCL? > > int func() > { > if( !__flag ) > { > call constructor > lock > do things > unlock > __flag = true; > } > } > > What prevents __flag = true migrating upwards above "do things"? Well, in your case, the lock and unlock would probably do it (ie by adding memory barriers). But you still need an acquire on the read of flag. Under Windows something like (off the top of my head): int func() { if( !InterlockedAddAcquire(&__flag, 0) ) { call constructor lock do things unlock InterlockedExchangeRelease(&__flag, true); } } Or set __flag = true inside the lock. I think your example isn't quite the exact DCLP example, but I know what you mean. static locals hasve been discussed on the list a number of times. Usually with the same problems and misplaced solutions, but somewhere in the discussion there will be some real solutions. I just want to templatize the solution for prosperity. Another way of looking at it is consider the case of making a 'StaticLocalCriticalSection' C++ object. Say this object wraps a Windows CRITICAL_SECTION (which needs an init) in a only-init-once way. How? class StaticLocalCriticalSection { atomic_int started; atomic_int initted; CRITICAL_SECTION cs; // this class must NOT have a constructor // (at least not one that does anything) // Instead we assume that we are static, // and thus 'started' and 'initted' are both set // to 0, effectively at compile time. void ensure_initted() { if (!AtomicExchange(&started, true)) { InitCriticalSection(&cs); AtomicExchange(&initted, true); } else { // There's better ways to do this than spinning, // but this is make the example shorter. // In fact, this example has a starvation problem, // if this thread has a higher priority // than the init thread. // (ie may never get a chance to be initted) while (!AtomicRead(&initted)) { Sleep(1); } } } public: void Enter() // enter the critical section { ensure_initted(); EnterCriticalSection(&cs); } void Leave() { ensure_initted(); // odd if not! LeaveCriticalSection(&cs); } }; So there's a critical section that can be used as a local static. You can then use that CS to protect your other local statics, or just use the same ensure_initted() type of logic inside a static_local template, and init a Foo instead of initting a criticalsection. And you will find the same/similar logic in call_once/pthread_once. That's why I say they are all 'equivalent' and given any one you can write the others. But, back to the original point of this thread (ie asking for opinions): from what I have seen, boost::call_once (and pthreads-win32 pthread_once) and my example are NOT the best way to implement 'ensure_initted'. Of course, it is just an implementation detail, so in some sense doesn't matter for standardization (each implementor can choose to do a better job). But it may or may not be an indicator of the quality of boost::threads. Actually, it probably is NOT an indicator - it is, in fact, just a small area of boost::threads. It just happens to be the only area I know much about... .