I ran into this problem when I was working on the SGI C++ Standard Template
Library. I don't know of a good solution, though I have a dim recollection
that someone told me more recently that this had been fixed. (I can't find
it on MSDN.) When I first ran into it, I sent a message to the threads
newsgroup asking how to do this, and received no completely correct
solutions. My conclusion was that you needed to roll your own using the
atomic exchange instruction. (That was never implemented. The current code
uses one of the partial solutions on win32, with a disclaimer in the header
file.) This probably argues it's not done correctly very often, though a
lot of half-way solutions are completely correct in specific cases.
As far as I could determine, the standard C++ constructor-based solution is
only correct about 95% of the time, at least if it's used inside something
like the STL, i.e. a library implemented primarily in header files. You can
always arrange to invoke something that requires the lock before the lock is
initialized. In particular, the following tends to break things:
void f();
<declare static variable A with constructor that calls f>
<include file that declares staically initialized lock, and function g that
needs lock>
f()
{
g();
}
This can look more natural if the declarations of f and A are in another
header file.
I haven't looked at the ACE implementation to see what it does.
Even from C, I believe there are ways to run initialization code at process
startup, or when a DLL is first loaded. My impression is that the
initialization code is run somewhat single-threaded, which causes a
different set of problems if the initialization code tries to lock. It also
doesn't help much with template-based libraries, I think. It would be nice
if someone more familiar with the APIs could clarify ...
In general, my impression is that C and C++ semantics are much less well
defined with threads than the Java semantics. What do bitfields mean in the
presence of threads? How many of the surrounding fields is the compiler
allowed to rewrite with a bitfield update? I haven't seen even an attempt
at an answer. Getting the Java spec right might be a good first step ...
Hans
> -----Original Message-----
> From: Doug Lea [mailto:dl@cs.oswego.edu]
> Sent: Monday, January 08, 2001 7:19 AM
> To: javaMemoryModel@cs.umd.edu
> Cc: schmidt@cs.wustl.edu
> Subject: JavaMemoryModel: static singletons in C on win32
>
>
>
> This is a little off the subject, but related to discussions of
> double-check and its variants. Maybe everyone else already knew this,
> but it was surprising to me.
>
> As far as I can see (I also checked with Doug Schmidt), there is
> no way to statically initialize a WIN32 CRITICAL_SECTION lock in C.
>
> In posix, this can be done via:
> static pthread_mutex_t amutex = PTHREAD_MUTEX_INITIALIZER;
>
> But in WIN32, you need to call InitializeCriticalSection() before you
> can use a lock. This makes it exceedingly tricky to define static
> singletons that need a static lock to protect construction. Trying to
> use double-check for the static lock itself of course leads to
> infinite regress. So I guess you'd need to roll-your-own
> dekker-algorithm locks or use raw CAS or test-and-set or somesuch? I
> wonder how many people get this right. Or maybe there is some
> workaround?
>
> In C++, you can wrap the CRITICAL_SECTION in a class that that will
> initialize it upon construction (as in ACE, and Schmidt et al's POSA2
> book). But even in this case, I don't know if C++ officially requires,
> and win32 runtimes actually provide, enough static initialization
> safeguards for this to occur reliably?
>
> -Doug
>
> -------------------------------
> JavaMemoryModel mailing list -
> http://www.cs.umd.edu/~pugh/java/memoryModel
>
-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel
This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:29 EDT