|
Boost : |
From: Anthony Williams (anthwil_at_[hidden])
Date: 2002-08-07 10:42:45
> From: William E. Kempf [mailto:williamkempf_at_[hidden]]
> Sent: 07 August 2002 15:34
> From: "Anthony Williams" <anthwil_at_[hidden]>
> Sent: Wednesday, August 07, 2002 4:06 AM
> > > From: William E. Kempf [mailto:williamkempf_at_[hidden]]
> > > From: "Anthony Williams" <anthwil_at_[hidden]>
> > > > > From: Peter Dimov [mailto:pdimov_at_[hidden]]
> > > > > From: "Anthony Williams" <anthwil_at_[hidden]>
> > > > > > > From: Peter Dimov [mailto:pdimov_at_[hidden]]
> > > > > > > From: "Pete Becker" <petebecker_at_[hidden]>
> > > > 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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk