From: William E. Kempf (williamkempf_at_[hidden])
Date: 2002-08-07 09:33:37


----- Original Message -----
From: "Anthony Williams" <anthwil_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Wednesday, August 07, 2002 4:06 AM
Subject: RE: [boost] Enhanced call_once()

> > 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.

> 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).

> 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.)

A simple implementation is trivial. However, there's some warts imposed on
the simple implementation, since it's a POD type. Those are:

* No private/protected data. The full implementation will be exposed on the
public interface. We can, however, declare this as implementation defined
making it an opaque type.

* No constructors. Minor point. You simply have to document that the only
valid construction pattern is:

static boost::static_mutex = BOOST_MUTEX_INIT;

* Compiler supplied copy and assignment operators. This is the part that
bothers me the most because copy/assignment are operations that should never
be done. Again, the best we probably can do is document it as resulting in
undefined behavior.

* The implementation must use only POD members. This one shouldn't cause
any real problems with the implementation but is still worth noting.

Bill Kempf