Subj : Re: Boost.Threads on its way to C++0x To : comp.programming.threads From : gottlobfrege Date : Thu Apr 28 2005 10:00 am Peter Dimov wrote: > gottlobfrege@gmail.com wrote: > > Peter Dimov wrote: > >> 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): [...] > > The problem I was trying to highlight is that __flag and all its > manipulations are implicitly done by the compiler. We don't have any control > over it and we can't insert an acquire on the initial load. No matter what > we do in the constructor, it can't be made to work reliably. Unless I'm > missing something. OK, I see what you are saying. I didn't read __flag as the hidden compiler flag - I thought you meant it was part of static_local<>'s implementation. The __ should have tipped me off. Anyhow, there is a subtlety that I have implemented in StaticLocalCriticalSection, but haven't considered in static_local<> (probably because I haven't found time to start implementing it yet). That is: for the CS, you do not do anything in the constructor - you have to wait until first use. So, for StaticLocalCriticalSection, every class method (Enter(), Leave(), etc) calls ensure_initted() before doing its stuff. Thus for static_local<>, which has _ptr syntax (auto_ptr, smart_ptr, etc) for operator->, etc (ie in the underlying get() call), you would have to do something similar like ensure_initted(). But static_local<> has a slightly bigger problem in that the constructor may have arguments passed in! (whereas the CriticalSection did not). So, what to do: 1. in the static_local<> constructor, we do ensure_initted(with ctor args as needed), using a 'started' flag, and an 'init' flag (and note that we can still get 2 contructors being called because the compiler's __flag is not thread safe). This is all similar to StaticLocalCriticalSection's ensure_initted, but just with constructor args. 2. in get(), we can't ensure_initted() because we don't even have the constructor args. Instead we have to call wait_initted(), where we can only wait for 'initted' to be set. Note that, since we are in get(), we know that either: - we went through the constructor, and thus initted is set or - we skipped the constructor (because of compiler __flag) and thus some other thread (1 or more!) got in and has constructed or is in the process of constructing. .