> From: William E. Kempf [mailto:williamkempf@hotmail.com]
> Sent: 07 August 2002 15:34
> From: "Anthony Williams" <anthwil@nortelnetworks.com>
> Sent: Wednesday, August 07, 2002 4:06 AM
> > > From: William E. Kempf [mailto:williamkempf@hotmail.com]
> > > From: "Anthony Williams" <anthwil@nortelnetworks.com>
> > > > > From: Peter Dimov [mailto:pdimov@mmltd.net]
> > > > > From: "Anthony Williams" <anthwil@nortelnetworks.com>
> > > > > > > From: Peter Dimov [mailto:pdimov@mmltd.net]
> > > > > > > From: "Pete Becker" <petebecker@acm.org>
> > > > So with Boost.Threads, you only have dynamic mutex
> > > initialization (with
> > > init
> > > > order problems), despite the fact that two of the three (I
> > > don't know
> > > > anything about MacOS) supported platforms have a mechanism
> > > for avoiding
> > > init
> > > > order problems with Mutexes?
> > >
> > > Yes, because those solutions aren't easy to apply to a C++
> > > class design.
> > > I'm working on it, but we don't have this yet.
> >
> > How hard can it be?
>
> Harder then you think.
Maybe.
> > For win32, you just lazy init using named mutexes (named
> after the address
> > of the mutex, and the process id, or something like that). To avoid
> multiple
> > calls to CreateMutex, you could use some flags, and the
> InterlockedXXX
> > functions:
>
> In other words, the implementation already found in
> boost::call_once. Yes,
> I know how to do this.
>
> [snip win32 code stuff]
>
> > Now it doesn't matter whether the mutex is statically or dynamically
> > initialized --- static objects are initialized to all zero
> before their
> > dynamic initialization, and reinitializing the flag to zero
> does no harm,
> as
> > CreateMutex will always return the same value.
>
> Just to be sure we're all using the same language here, when
> I say "static
> initialization" I mean the definition stated in 3.6.2/1.
> This requires a
> POD type. The code you posted isn't POD and can't be statically
> initialized. In particular this means the call to your
> constructor may not
> have occurred when a thread started before main attempts to
> call lock(), and
> thus the lazyInit() will likey not get called either (though
> it's undefined
> behavior).
I was referring to that paragraph. "The storage for objects with static storage duration shall be zero-initialized before any other initialization takes place" (first sentence) therefore all the members of a static instance of my (non-POD) mutex class are initialized to zero at startup. If the compiler takes the leeway of 3.6.2p2 to do the dynamic initialization statically (since the constructor only initializes flag to zero, it can do this) all is --- flag is zero on startup, and never re-zeroed, just set to 1 when lazyInit is called.
If the compiler doesn't take this leeway, and performs explicit dynamic initialization, then we may indeed enter the territory of undefined behaviour if any thread calls lock before the constructor is completed.
However, in practice, we are targetting a specific platform, and may be able to get guarantees from the compilers about whether or not such an object would be dynamically initialized, and the consequences in such a case.
Maybe trying to avoid the call to CreateMutex when it is already created is a lost cause.
> > For POSIX, we can use pthread_once to lazy-init the mutex.
>
> Which requires a statically initialized pthread_once_t, so
> again, the mutex
> type has to be POD. (At which point you'd be better off
> using a statically
> initialized mutex then a call to pthread_once.)
Yes, I had forgotten that. However, you can use pthread_once within the library to initialize some global data, and then lazy init the mutex --- see my reply to Peter Dimov.
[snipped constraints on POD mutex classes]
I agree that we want to avoid a POD mutex class if possible. I am trying to find a way.
However, unless we can guarantee that a non-POD with a simple constructor is statically initialized as per the leeway of 8.6.2p2, we leave ourselves exposed to the possibility of undefined behaviour if any of the member functions are called before the constructor has completed.
In practice, I can't imagine a compiler _not_ doing static initialization for a simple inline constructor that assigned constants to the members.
Anthony