Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

singleton + multithreading + static initialization

31 views
Skip to first unread message

Swampmonster

unread,
Dec 14, 2004, 3:32:37 PM12/14/04
to
Hi!

Now this is a little hard to describe for me, so please indulge my
clumsy description :(

As the topic might suggest I'm looking for a foolproof (and
standard-compliant) way to implement the singleton pattern in C++, in a
multithreaded environment, and without relying on some compiler-feature
that might be known but is not required by the standard.
Ah yes, and of course one that does work in reallity with real
compilers. At least MSVC 7.1 in my case - the more the better.

My first attempt was like this:

class singleton { ... };

singleton& singleton::get_instance( )
{
static singleton the_instance;
return the_instance;
}

Now that looks o.k., but when I looked at the code generated by MSVC 7.1
I noticed that the call to singleton's constructor was in no way guarded
against concurrent execution on 2 or more threads. It's just a:
if(!flag)
{
flag = true;
construct_object();
}
thingy which will work in 99+% of all cases and crash exactly "when
murphy wants it to".
(Btw: does the C++ standard say anything about that situation?)

So. The next idea was to implement the synchronisation myself. Of course
this will require some platform dependent code, but let's just assume we
have some "mutex" class that's instances are (once fully constructed)
the synchronization-object in itself, so to synchronize access one would
have to call "lock()/unlock()" on the same instance of the class. So in
other words, let's say this mutex behaves something like MFC's CMutex
when using unnamed mutexes.
This again sounds promising, but I soon realized that it only shifts the
point where we encounter problems from where the actual singleton is
constructed to where the mutex is constructed; since now the mutex is a
singleton, and the situation is the same as before - how to construct
that mutex in a thread-safe way?
Of course using win32's named mutexes solves the problem (because then
we can use nonstatic locals for the mutex instance which refer to the
same synchronization-primitive by name, and the win32 subsystem takes
care of serialising construction/access etc.), but it's a) not nearly as
portable to require such "named mutexes" than to require just "unnamed
mutexes" and b) I suppose it to be very slow (and it is when using
win32's ::CreateMutex()). The "very slow" thing could be solved by
double-checked locking (then singleton::get_instance() would use "new
singleton()" instead of a local static and all that), but then again,
who should guard the initialization of the flag for the double-checked
locking?

One way to solve the problem is to make the mutex instance a static
member variable of the singleton-class (or any class, or a "global").
That way it's guaranteed to be fully constructed after the static
initialization phase. And because of the "static initialization order
desaster" thingy, we have to forbid the use of the
singleton::get_instance() function until all static initialization is
done, i.e. forbid calls to singleton::get_instance() from every function
that could be called from a constructor of a class that might be
instantiated statically (except for local statics where the "owning"
function is never executed and so on and so forth).

All the singleton-implementations I've seen so far do it somewhat like
this (or even impose more constraints, sometimes documented sometimes
not), but I'm not quite happy with the solution. I do think
instantiating stuff statically (at namespace scope) is "bad" C++, but
then again I don't like the idea to forbid any user of a library I write
to do it with my classes.

So. Simple question now: Can it be done? Is there a way to have that
kind of foolproof-std.-compliant-and-in-reality-working singleton
implementation? And, ah, let's just ignore the destruction of the
singleton for the moment - let's say I'm happy with the well-known
"atexit()" approach.
Sorry if something is unclear, just ask and I'll try to clarify it.

Regards,
'monster

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Kurt Krueckeberg

unread,
Dec 14, 2004, 8:38:15 PM12/14/04
to

">
> Now this is a little hard to describe for me, so please indulge my
> clumsy description :(
>
> As the topic might suggest I'm looking for a foolproof (and
> standard-compliant) way to implement the singleton pattern in C++, in a
> multithreaded environment, and without relying on some compiler-feature
> that might be known but is not required by the standard.
> Ah yes, and of course one that does work in reallity with real
> compilers. At least MSVC 7.1 in my case - the more the better.
>
> My first attempt was like this:
>
> class singleton { ... };
>
> singleton& singleton::get_instance( )
> {
> static singleton the_instance;
> return the_instance;
> }
>
> Now that looks o.k., but when I looked at the code generated by MSVC 7.1
> I noticed that the call to singleton's constructor was in no way guarded
> against concurrent execution on 2 or more threads. It's just a:
> if(!flag)
> {
> flag = true;
> construct_object();
> }
>
Look at the double-check pattern as it applies to Singleton.
Confer http://www.cs.wustl.edu/~schmidt/PDF/DC-Locking.pdf.
Use a CRITICAL_SECTION instead of a mutex. It's faster.

class SynObject { // base for synchronization objects--critical sections,
mutexs, events, semaphores.
public:
SynObject() : locked_(false), t_(t) {}

virtual bool Lock(unsigned long = INFINITE) = 0;
virtual bool Unlock()=0;

virtual ~SynObject()
{
if (locked_ == true)
Unlock();
}

private:
bool locked_;
};

bool SynObect::Lock(unsigned long = INFINITE) { locked_ = true; return
true;}
bool SynObject::Unlock() { locked_ = false; return true;}

class CriticalSection : public SynObject {
public:
CriticalSection() { ::InitializeCriticalSection(&cs_);}
~CriticalSection() { ::DeleteCriticalSection(&cs_); }

bool Lock()
{
locked_ = true;
::EnterCriticalSection(&cs_);
return true;
}

bool Unlock()
{
::LeaveCriticalSection(&cs_);
locked_ = false;
return true;
}
private:
CRITICAL_SECTION cs_;
};


template <class T> class Lock { // applies "resource acquisition is
intialization" idiom to synchronization objects
T& obj_;
public:
Lock(T& obj) : obj_(obj) {
obj.Lock();
}
~Lock() {
obj_.Unlock();
}
};


class Singleton {
public:
static Singleton *instance (void)
{
static CriticalSection cs;
// First check
if (instance_ == 0) {

// Ensure serialization (guard constructor acquires lock_).
Lock<CriticalSection> guard (cs);

// Double check.
if (instance_ == 0)
instance_ = new Singleton;
}

return instance_;
// guard destructor releases lock_.
}
private:
static Singleton *instance_;
};

Ben Hutchings

unread,
Dec 14, 2004, 11:46:17 PM12/14/04
to
Swampmonster wrote:
<snip>
> One way to solve the problem is to make the mutex instance a static
> member variable of the singleton-class (or any class, or a "global").
> That way it's guaranteed to be fully constructed after the static
> initialization phase. And because of the "static initialization order
> desaster" thingy, we have to forbid the use of the
> singleton::get_instance() function until all static initialization is
> done, i.e. forbid calls to singleton::get_instance() from every function
> that could be called from a constructor of a class that might be
> instantiated statically (except for local statics where the "owning"
> function is never executed and so on and so forth).
<snip>

I found a way to avoid the static initialisation disaster (which is
really a misnomer, as it relates to *dynamic* initialisation of static
variables). The idea is to do initialisation in functions which can
call other initialisation functions, with dynamic initialisation used
only to make sure that those functions without dependencies still get
called.

Here's a simple implementation:

enum call_once_flag { not_done = 0, in_progress, done };

void call_once(void (*func)(), call_once_flag & flag)
{
assert(flag != in_progress || !"cyclic initialisation dependency");
if (flag == not_done)
{
flag = in_progress;
func();
flag = done;
}
}

template<void (*func)()>
class early_init
{
private:
// The classes are not intended to be instantiated.
early_init();

public:
// Do initialisation now if it has not yet been done.
static void ensure() { call_once(func, flag_); }

private:
static call_once_flag flag_;
};

// This will be statically initialised to not_done, then changed
// to done by call_once, then set to done again by its dynamic
// initialisation.
template<void (*func)()>
call_once_flag early_init<func>::flag_ = (ensure(), done);

Now for each initialisation function, you must define a function
pointer along these lines:

void (*my_init)() = early_init<my_internal_init>::ensure;

and other initialisation functions that depend on its work should call
it through that function pointer.

(This should be all you need to do because it causes ensure to be
instantiated, which causes flag_ to be instantiated, which means
ensure will definitely be called eventually.)

--
Ben Hutchings
compatible: Gracefully accepts erroneous data from any source

jto...@yahoo.com

unread,
Dec 15, 2004, 5:47:06 AM12/15/04
to
The pseudocode should be like:

static mutex cs;
static bool initialized;
thread_specific_bool &local_initialized = ...;

if ( !local_initialized {
scoped_lock lock(cs);
if ( initialized) {
local_initialized = true;
return value;
}
// initialize now
value = singleton(...);
local_initialized = true;
initialized = true;
}
return value;


Best,
John

--
John Torjo, Contributing editor, C/C++ Users Journal
-- "Win32 GUI Generics" -- generics & GUI do mix, after all
-- http://www.torjo.com/win32gui/
-- http://www.torjo.com/cb/ - Click, Build, Run!

Branimir Maksimovic

unread,
Dec 15, 2004, 8:07:54 AM12/15/04
to

Swampmonster wrote:
> Hi!
>
> Now this is a little hard to describe for me, so please indulge my
> clumsy description :(
>
> As the topic might suggest I'm looking for a foolproof (and
> standard-compliant) way to implement the singleton pattern in C++, in
a
> multithreaded environment, and without relying on some
compiler-feature
> that might be known but is not required by the standard.

I guess posix provides only portable way to deal with threads
for now.
For singletons use pthread_once mechanism which is provided
by it. In same way global and static mutexes can be initialized.

class Singleton{
public:
Singleton& instance()
{
pthread_once(&is_initialised_, &initialize);
return *instance_;
}
private:
static void initialize()
{
instance_ = new Singleton();
atexit(&destroy);
}
static void destroy()
{
delete instance_;
instance_ = 0;
is_initialised_ = PTHREAD_ONCE_INIT;
}
static Singleton* instance_;
static pthread_once_t is_initialised_;
};

Singleton* Singleton::instance_;
pthread_once_t Singleton::is_initialised_ = PTHREAD_ONCE_INIT;

This is pretty simple and efficient as implementors
of pthread_once can perform all sort of optimisations
for this particular purpose.

Greetings, Bane.

P.S. if posix libs uses c calling convention look at recent thread
about static member functions and extern "C".

Vladimir Marko

unread,
Dec 15, 2004, 11:36:12 AM12/15/04
to
jto...@yahoo.com wrote:
> The pseudocode should be like:
>
> static mutex cs;
> static bool initialized;
> thread_specific_bool &local_initialized = ...;
>
> if ( !local_initialized {
> scoped_lock lock(cs);
> if ( initialized) {
> local_initialized = true;
> return value;
> }
> // initialize now
> value = singleton(...);
> local_initialized = true;
> initialized = true;
> }
> return value;

As the OP wrote this only moves the problem from the
initialization of the singleton to the initialization of the
mutex. The name "cs" of your mutex suggests that it could be
a CRITICAL_SECTION under win32. I'm not sure. I don't know
the CRITICAL_SECTION good enough to say if it is safe to,
say, InitializeCS, EnterCS, switch thread, InitializeCS,
TryEnterCS. Or even InitializeCS twice (?!), since my tests
show that DestroyCS clears the CS's data, thus trying to
match two InitializeCSs with two DestroyCSs is useless.

I've been thinking about this recently and the only really
safe initialization I was able to find was the OP's named
mutex option with the name containing CurrentProcessID
to avoid process interaction. All threads try to write
_the same pid_ to the _staticaly initialized_ "static char
mutex_name[]=..." so it should be safe to expect the name
to be set correctly. However, I'm paranoid enough to use
InterlockedExchange even for these seemingly safe writes.

Best,
Vladimir Marko

PS: I think this has nothing to do with C++ and should be
discussed at comp.programming.threads instead.

ka...@gabi-soft.fr

unread,
Dec 15, 2004, 1:19:45 PM12/15/04
to
Swampmonster wrote:

[Classical initialization problem: protecting the creation of a
mutex...]

> So. Simple question now: Can it be done? Is there a way to have that
> kind of foolproof-std.-compliant-and-in-reality-working singleton
> implementation?

The easiest solution, of course, is to just forget about Windows, and
use Posix:-) -- Posix has a purely static initializer for a mutex, if
you only need default initialization.

More realistically, I've recently adopted a trick that works portably
for singletons, AND avoids the necessity of locking each time you want
to access it:

class Singleton
{
public:
static Singleton& instance() ;
// ...
private:
static Singleton* ourInstance ;
} ;

And in the .cc:

Singleton* Singleton::ourInstance = &Singleton::instance() ;

Singleton&
Singleton::instance()
{
if ( ourInstance == NULL ) {
ourInstance = new Singleton ;
}
return *ourInstance ;
}

It's a bit sneaky, as it counts on the double initialization defined in
the standard: zero initialization before any dynamic initialization.
And the only thing it really does is guarantee that Singleton::instance
will be called at least once during the initialization of static
variables. (After the first call to Singleton::instance, of course,
ourInstance is immutable, so access to it doesn't need to be
protectetd.)

It does require that you don't start multithreading until after main is
entered, but this isn't normally a problem.

It also requires that all dynamic initialization of static variables
take place before entering main; the standard doesn't require this, but
it is the case with all compilers I know, and so much code depends on
it
that I don't think a compiler would dare do otherwise.

Note that a similar pattern can be used to create your mutexes -- just
make a separate singleton (or implement something similar) for each
one.

> And, ah, let's just ignore the destruction of the singleton for the
> moment - let's say I'm happy with the well-known "atexit()" approach.

In practice, I find it generally preferable to never destruct the
singleton. Which is what the above solution does.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

ka...@gabi-soft.fr

unread,
Dec 15, 2004, 1:20:08 PM12/15/04
to
Kurt Krueckeberg wrote:

> Look at the double-check pattern as it applies to Singleton.
> Confer http://www.cs.wustl.edu/~schmidt/PDF/DC-Locking.pdf.

This has been thrashed out I don't know how many times now. Double
checked locking doesn't work in general. (I think it is guaranteed to
work with a single processor Intel machine, but that's about the limit
of it.)

In addition, of course, it doesn't address his problem of how to create
the mutex in the first place.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

ka...@gabi-soft.fr

unread,
Dec 15, 2004, 1:51:06 PM12/15/04
to
Branimir Maksimovic wrote:
> Swampmonster wrote:

> > Now this is a little hard to describe for me, so please indulge my
> > clumsy description :(

> > As the topic might suggest I'm looking for a foolproof (and
> > standard-compliant) way to implement the singleton pattern in C++,
> > in a multithreaded environment, and without relying on some
> > compiler-feature that might be known but is not required by the
> > standard.

> I guess posix provides only portable way to deal with threads for
now.
> For singletons use pthread_once mechanism which is provided by it.

Boost offers similar functionality for both Posix and Windows. Don't
know the details, though.

> In same way global and static mutexes can be initialized.

> class Singleton{
> public:
> Singleton& instance()
> {
> pthread_once(&is_initialised_, &initialize);
> return *instance_;
> }
> private:
> static void initialize()
> {
> instance_ = new Singleton();
> atexit(&destroy);
> }
> static void destroy()
> {
> delete instance_;
> instance_ = 0;
> is_initialised_ = PTHREAD_ONCE_INIT;
> }
> static Singleton* instance_;
> static pthread_once_t is_initialised_;
> };

> Singleton* Singleton::instance_;
> pthread_once_t Singleton::is_initialised_ = PTHREAD_ONCE_INIT;

There is a slight problem with your implementation: it isn't legal C++,
and a C++ shouldn't compile it (and some don't). The function you pass
to pthread_once must be declared `extern "C"', which means that it
cannot be a member, static or otherwise. Making it a non-member means
making most of the data public. The solution I usually use for this is
to put the non-member function and all of the static data it needs in
an
anonymous namespace in the implementation file -- this of course means
that you cannot inline the definitions of the functions, but that's not
usually a problem. It also means that you cannot templatize it, which
is a bit more of a pain -- it is boilerplate, after all.

> This is pretty simple and efficient as implementors
> of pthread_once can perform all sort of optimisations
> for this particular purpose.

Can. Does it on your implementation? (The canonical implementation of
pthread_once is:

pthread_mutex_lock( &somePreconstructedMutex ) ;
if ( ! flag ) {
(*userFunction)() ;
flag = true ;
}
pthread_mutex_unlock( &somePreconstructedMutex ) ;

> P.S. if posix libs uses c calling convention look at recent thread
> about static member functions and extern "C".

Posix libs do use a C calling convention, and any pointers to function
passed to them must pass an extern "C" function.

On most machines -- maybe even all, you can fudge with a
reinterpret_cast, and the code will work anyway. I'd hate to have to
defend that code in a code review, though. (On the other hand, it's
probably the only way to write a Singleton template.)

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

ka...@gabi-soft.fr

unread,
Dec 15, 2004, 1:53:22 PM12/15/04
to
jto...@yahoo.com wrote:
> The pseudocode should be like:

> static mutex cs;
> static bool initialized;
> thread_specific_bool &local_initialized = ...;

> if ( !local_initialized {
> scoped_lock lock(cs);
> if ( initialized) {
> local_initialized = true;
> return value;
> }
> // initialize now
> value = singleton(...);
> local_initialized = true;
> initialized = true;
> }
> return value;

Which fails to address his basic problem: how do you ensure that the
mutex (cs in your code) is initialized before the function which uses
it
is called? (Also, accessing thread specific memory can be expensive on
some platforms. Classically, you acquire a mutex, then look up the
data
in a map. If thread specific memory is cheap, however, this is an
implementation of double checked locking which will work.)

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Swampmonster

unread,
Dec 16, 2004, 8:26:08 AM12/16/04
to
Allan W wrote:
> This is much more complicated than it needs to be.
>
> Try this:
>
> . // Singleton.h
> . class Singleton {
> . Singleton(); // Private constructor
> . // Not implemented:
> . Singleton(Singleton &); // NO copy ctor
> . void operator=(Singleton &); // NO assignment
> . public:
> . static singleton theInstance; // The one and only instance
> . static void initSingleton(); // Called by main()
> . // ... whatever ...
> . };
>
> . // Singleton.cpp
> . Singleton Singleton::theInstance;
> . static void Singleton::initSingleton() {
> . Singleton *t = &theInstance;
> . }
>
> Now, your main() function must call Singleton::initSingleton() before
> it creates any threads.
> (Please tell me you're not creating threads before main() starts!)
> When (or before) flow of control reaches the Singleton.cpp translation
> unit, it creates the Singleton.
> After that, you use the one-and-only instance... no mutexes needed.
>
> In single-thread applications, calling Singleton::initSingleton() is
> optional, but does no harm.

>
>
> [ See http://www.gotw.ca/resources/clcm.htm for info about ]
> [ comp.lang.c++.moderated. First time posters: Do this! ]

Well. I'm writing a .LIB. If I was just doing some code all on my own or
only with guys I know I wouldn't have a problem.
Bye,

Swampmonster

unread,
Dec 16, 2004, 8:25:38 AM12/16/04
to
Vladimir Marko wrote:
> I've been thinking about this recently and the only really
> safe initialization I was able to find was the OP's named
> mutex option with the name containing CurrentProcessID
> to avoid process interaction. All threads try to write
> _the same pid_ to the _staticaly initialized_ "static char
> mutex_name[]=..." so it should be safe to expect the name
> to be set correctly. However, I'm paranoid enough to use
> InterlockedExchange even for these seemingly safe writes.

Hi!
Instead of just one char[] you could use many local char[]s. I agree
that overwriting data with the same data should be safe, but with locals
one wouldn't have to think about it.
And no, this is IMHO no general programming topic, because how to
achieve it is so different from language to language (I'm 99% sure that
e.g. Java provides safe static init' on it's own and 90% that C# does).
Bye,
'monster

Allan W

unread,
Dec 16, 2004, 8:28:02 AM12/16/04
to
This is more complicated than you need.

Call get_instance() once from main(), before you create any threads.
This will cause the singleton to be created before any threads have
started. No mutex needed, works 100% of the time.

Branimir Maksimovic

unread,
Dec 16, 2004, 8:26:42 AM12/16/04
to
ka...@gabi-soft.fr wrote:
> Branimir Maksimovic wrote:
> > Swampmonster wrote:
>
> > > Now this is a little hard to describe for me, so please indulge
my
> > > clumsy description :(
>
> > > As the topic might suggest I'm looking for a foolproof (and
> > > standard-compliant) way to implement the singleton pattern in
C++,
> > > in a multithreaded environment, and without relying on some
> > > compiler-feature that might be known but is not required by the
> > > standard.
>
> > I guess posix provides only portable way to deal with threads for
> now.
> > For singletons use pthread_once mechanism which is provided by it.
>
> Boost offers similar functionality for both Posix and Windows. Don't
> know the details, though.

You must carry boost with code everywhere, but pthreads only to
windows,
and perhaps some older exotic platforms :)
http://ftp.tw.xemacs.org/pub/sourceware/pthreads-win32/sources/pthreads-snap-2004-11-22/

<code snip>

>
> There is a slight problem with your implementation: it isn't legal
C++,
> and a C++ shouldn't compile it (and some don't).

Implementations where extern "C" pointer is not same as ordinary
c++ function pointer would not compile this and *that* is pain.

The function you pass
> to pthread_once must be declared `extern "C"', which means that it
> cannot be a member, static or otherwise.

Look at thread about using static member functions as C callbacks.
I've discovered that this is legal in c++

extern "C"
{
typedef void func_t();
}

struct X{
static func_t func;
};

extern"C"
void X::func()
{
}

compiles with gcc 3.2.2, but not with gcc 2.95.3
as later compiler complains about different specifications of
declaration/definition.


>
> > This is pretty simple and efficient as implementors
> > of pthread_once can perform all sort of optimisations
> > for this particular purpose.
>
> Can. Does it on your implementation?

Look at source for pthreads for win32. I didn't look for linux,
as I was curious about windows pthreads.
http://ftp.tw.xemacs.org/pub/sourceware/pthreads-win32/sources/pthreads-snap-2004-11-22/pthread_once.c

>(The canonical implementation of
> pthread_once is:
>
> pthread_mutex_lock( &somePreconstructedMutex ) ;
> if ( ! flag ) {
> (*userFunction)() ;
> flag = true ;
> }
> pthread_mutex_unlock( &somePreconstructedMutex ) ;

That would be very bad implementation.
If pthread_once should use mutex why bother with it after all.
When testing on linux implementation I don't notice any
lock contention when using this function.
Lot of code relies on quality of such functions.

>
> > P.S. if posix libs uses c calling convention look at recent thread
> > about static member functions and extern "C".
>
> Posix libs do use a C calling convention, and any pointers to
function
> passed to them must pass an extern "C" function.

Yes, you are right, but lot's of implementations of c++ use
same calling convention as c compiler, and those don't differ
between c and c++ function pointers.

>
> On most machines -- maybe even all, you can fudge with a
> reinterpret_cast, and the code will work anyway.

Nope. One way reinterpet_cast means this won't work, and if
works it shouldn't, so better let it be as it is.
If code compiles, thats fine, but if does not compiles, then extern "C"
is better solution as reinterpret_cast would lead to crash.

I'd hate to have to
> defend that code in a code review, though. (On the other hand, it's
> probably the only way to write a Singleton template.)

Thanks to this group I've discovered that static member functions
can be declared as extern "C" through typedef and defined accordingly,
so template Singleton is still possible.
Though compiler has to support this, as gcc 2.95.3 ignores extern "C"
specification, but gcc 3.2.2 does not.

Greetings, Bane.

Randy

unread,
Dec 16, 2004, 8:37:24 AM12/16/04
to

ka...@gabi-soft.fr wrote:

[snip]

>
> There is a slight problem with your implementation: it isn't legal
C++,
> and a C++ shouldn't compile it (and some don't). The function you
pass
> to pthread_once must be declared `extern "C"', which means that it
> cannot be a member, static or otherwise.

[snip]

>
> --
> James Kanze GABI Software http://www.gabi-soft.fr
> Conseils en informatique orientée objet/
> Beratung in objektorientierter Datenverarbeitung
> 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
>
>

Is the above statement correct? I certainly hesitate before
questioning one of your standing, however there was a recent thread in
which Francis Glassborow offered the following example for making a
static member function have extern "C" linkage:

extern "C"
{
typedef void (f_c)(int);
}

struct X
{
static f_c foo;
};

Does that not work?

Thanks.

Randy.

Swampmonster

unread,
Dec 16, 2004, 8:42:57 AM12/16/04
to
ka...@gabi-soft.fr wrote:
> This has been thrashed out I don't know how many times now. Double
> checked locking doesn't work in general. (I think it is guaranteed to
> work with a single processor Intel machine, but that's about the limit
> of it.)

Hm. What does the standard say about concurrent read/write of builtin
types - e.g. a volatile int? Does it say the read _value_ is undefined,
and the write succeeds anyway (with the int having the correct value
after that, and no undefined behaviour except the read value of that
int), or does it say something worse like undefined behaviour in
general? In the first case it would work anyway, in the second ... well
then of course anything could happen.

Swampmonster

unread,
Dec 16, 2004, 8:44:23 AM12/16/04
to
> Boost offers similar functionality for both Posix and Windows. Don't
> know the details, though.

Boost (looked it up today, realizing that I had missed some parts of the
boost::threads lib) uses a named mutex on windoze and pthreads
otherwise. And one other thing I for one other platform - but I don't
remember what it was...

>>This is pretty simple and efficient as implementors
>>of pthread_once can perform all sort of optimisations
>>for this particular purpose.
>
>
> Can. Does it on your implementation? (The canonical implementation of
> pthread_once is:
>
> pthread_mutex_lock( &somePreconstructedMutex ) ;
> if ( ! flag ) {
> (*userFunction)() ;
> flag = true ;
> }
> pthread_mutex_unlock( &somePreconstructedMutex ) ;
>
>
>>P.S. if posix libs uses c calling convention look at recent thread
>>about static member functions and extern "C".
>
>
> Posix libs do use a C calling convention, and any pointers to function
> passed to them must pass an extern "C" function.

Ouch. No exceptions then allowed in the "init_once()" code (the
"canonical" implementation would deadlock)... but one could deal with that.

> On most machines -- maybe even all, you can fudge with a
> reinterpret_cast, and the code will work anyway. I'd hate to have to
> defend that code in a code review, though.

Such stuff is exactly what I'm trying to avoid :-)

> (On the other hand, it's
> probably the only way to write a Singleton template.)

I think one could use that 'extern "C"' function to init the mutex and
return a pointer or store the mutex's address in some global. Then have
some global function "hidden" in some detail-namespace call that extern
"C" function, check that pointer (e.g. call unexpected() if it's null),
and return a ref. Then the template could just call that "hidden in
namespace" C++ function to get to the initialized mutex's ref, and use
it. Or did you mean something else?

Bye,
'monster

Falk Tannhäuser

unread,
Dec 16, 2004, 1:16:08 PM12/16/04
to
Randy wrote:

> ka...@gabi-soft.fr wrote:
>> There is a slight problem with your implementation: it isn't legal C++,
>> and a C++ shouldn't compile it (and some don't). The function you pass
>> to pthread_once must be declared `extern "C"', which means that it
>> cannot be a member, static or otherwise.
>
> Is the above statement correct? I certainly hesitate before
> questioning one of your standing, however there was a recent thread in
> which Francis Glassborow offered the following example for making a
> static member function have extern "C" linkage:
>
> extern "C"
> {
> typedef void (f_c)(int);
> }
>
> struct X
> {
> static f_c foo;
> };
>
> Does that not work?

No, it doesn't - according to § 7.5/4, the C language linkage is ignored.


I'm still looking for an authoritative answer to know if template functions
can be 'extern "C"' (both Comeau and g++ think so, but g++ doesn't take into
account linkage specifications for function pointer types anyway) since I
couldn't find anything in the Standard on this subject. If it were standard
conforming, the following would solve the problem:

extern "C" { typedef void pthread_once_entry_routine(); }

template<void (&fun_ptr)()> pthread_once_entry_routine extern_C_wrapper; // declaration
template<void (&fun_ptr)()> void extern_C_wrapper() { fun_ptr(); } // definition

...
pthread_once(&is_initialised_, extern_C_wrapper<Singleton::initialize>);


Falk

Ben Hutchings

unread,
Dec 16, 2004, 1:14:37 PM12/16/04
to
Kurt Krueckeberg wrote:
<snip>
> Look at the double-check pattern as it applies to Singleton.
> Confer http://www.cs.wustl.edu/~schmidt/PDF/DC-Locking.pdf.

DON'T DO THIS, because it doesn't work. See
<http://c2.com/cgi/wiki?DoubleCheckedLockingIsBroken>.

> Use a CRITICAL_SECTION instead of a mutex. It's faster.

Win32's CRITICAL_SECTION *is* a mutex.

> class SynObject { // base for synchronization objects--critical sections,
> mutexs, events, semaphores.
> public:
> SynObject() : locked_(false), t_(t) {}
>
> virtual bool Lock(unsigned long = INFINITE) = 0;
> virtual bool Unlock()=0;
>
> virtual ~SynObject()
> {
> if (locked_ == true)
> Unlock();
> }

This hides errors. Shouldn't it be assert(!locked_)?

> private:
> bool locked_;
> };
>
> bool SynObect::Lock(unsigned long = INFINITE) { locked_ = true; return
> true;}
> bool SynObject::Unlock() { locked_ = false; return true;}

What is the point of these?

> class CriticalSection : public SynObject {
> public:
> CriticalSection() { ::InitializeCriticalSection(&cs_);}
> ~CriticalSection() { ::DeleteCriticalSection(&cs_); }
>
> bool Lock()

<snip>
> bool Unlock()
<snip>

why make these public when they can only safely be used by Lock?

--
Ben Hutchings
This sentence contradicts itself - no actually it doesn't.

Vladimir Marko

unread,
Dec 16, 2004, 1:15:03 PM12/16/04
to
Hi!

Swampmonster wrote:
> Vladimir Marko wrote:
> > I've been thinking about this recently and the only really
> > safe initialization I was able to find was the OP's named
> > mutex option with the name containing CurrentProcessID
> > to avoid process interaction. All threads try to write
> > _the same pid_ to the _staticaly initialized_ "static char
> > mutex_name[]=..." so it should be safe to expect the name
> > to be set correctly. However, I'm paranoid enough to use
> > InterlockedExchange even for these seemingly safe writes.
>
> Hi!
> Instead of just one char[] you could use many local char[]s. I agree
> that overwriting data with the same data should be safe, but with
locals
> one wouldn't have to think about it.

You're right. My implicit optimization techniques took over
even though I explicitly decided not to optimize the function.
With the need for thread safety I messed up.

> And no, this is IMHO no general programming topic, because how to
> achieve it is so different from language to language (I'm 99% sure
that
> e.g. Java provides safe static init' on it's own and 90% that C#
does).
> Bye,
> 'monster

It's not different from language to language. It's just that
it's already implemented in some languages and these provide
different constructs to use it. May be we should ask the
implementers for the know-how.

I think clc++m is the wrong group for this discussion also
because the ISO 14882 implicitly uses a single threaded
abstract machine. There are some proposals to add multi
threading into the standard, but AFAICS these are in very
early stages. See for example

http://www2.open-std.org/jtc1/sc22/WG21/docs/papers/2004/n1738.pdf
Regards,
Vladimir Marko

Branimir Maksimovic

unread,
Dec 16, 2004, 1:16:31 PM12/16/04
to

> >>This is pretty simple and efficient as implementors
> >>of pthread_once can perform all sort of optimisations
> >>for this particular purpose.
> >
> >
> > Can. Does it on your implementation? (The canonical
implementation of
> > pthread_once is:
> >
> > pthread_mutex_lock( &somePreconstructedMutex ) ;
> > if ( ! flag ) {
> > (*userFunction)() ;
> > flag = true ;
> > }
> > pthread_mutex_unlock( &somePreconstructedMutex ) ;
> >
> >
> >>P.S. if posix libs uses c calling convention look at recent thread
> >>about static member functions and extern "C".
> >
> >
> > Posix libs do use a C calling convention, and any pointers to
function
> > passed to them must pass an extern "C" function.
>
> Ouch. No exceptions then allowed in the "init_once()" code (the
> "canonical" implementation would deadlock)... but one could deal with
that.

This is minor problem. pthread_once should assure proper
behavior when dealing with thread cancelation and forking
during initialization so this is not cannonical implementation.
BTW I've looked at windows implementation and it did not
assure that as well.
Perhaps on windows there is no such
thing as thread cancelation or forking, but anyways.
Linux implementation uses mutex, but for different reasons.
There is no locking when initialisation is performed
and it works well with multiple CPU's.

Greetings, Bane.

P.S. named mutex is very expensive, if boost uses it.

Branimir Maksimovic

unread,
Dec 16, 2004, 11:44:45 PM12/16/04
to

ka...@gabi-soft.fr wrote:
> Branimir Maksimovic wrote:
>
>
> > In same way global and static mutexes can be initialized.
>
> > class Singleton{
> > public:
> > Singleton& instance()
> > {
> > pthread_once(&is_initialised_, &initialize);
> > return *instance_;
> > }
> > private:
> > static void initialize()
> > {
> > instance_ = new Singleton();
> > atexit(&destroy);
> > }
> > static void destroy()
> > {
> > delete instance_;
> > instance_ = 0;
> > is_initialised_ = PTHREAD_ONCE_INIT;
> > }
> > static Singleton* instance_;
> > static pthread_once_t is_initialised_;
> > };
>
> > Singleton* Singleton::instance_;
> > pthread_once_t Singleton::is_initialised_ = PTHREAD_ONCE_INIT;
>
> There is a slight problem with your implementation: it isn't legal
C++,
> and a C++ shouldn't compile it (and some don't).

I checked pthread.h header and you are wrong in this case.
There is no sign of extern "C" in any of function declarations.
Because this interface works both for c and c++ that means
implementors know what are they doing.
Why isn't legal c++. What is said about pthread_once?
if particular implementation have identical c and c++
function pointers and calling convention, why use extern "C"
after all.
And if implementors put extern "C" in front of declarations,
code won't compile and that's a good thing.
But nobody obligates implementors to put extern"C" specifiers
if that is not necessary. posix specifies c, but both
c and c++ can read same headers with no problem.

Greetings, Bane.

Branimir Maksimovic

unread,
Dec 16, 2004, 11:45:07 PM12/16/04
to

ka...@gabi-soft.fr wrote:
> Branimir Maksimovic wrote:
> > Swampmonster wrote:
>
> There is a slight problem with your implementation: it isn't legal
C++,
> and a C++ shouldn't compile it (and some don't).
Appologies for previous post. I've exampined pthread.h bit more
thoroughly and concluded that you are right.
extern "C" specifier is hidden in macro which is defined in another
file. So actually, pthread_once
is declared as c function, my example should'nt compile at all
even on platform I'm using.

from sys/cdefs.h
/* C++ needs to know that types and declarations are C, not C++. */
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif

Greetings, Bane.

James Talbut

unread,
Dec 17, 2004, 6:12:51 AM12/17/04
to
"Ben Hutchings" <ben-publ...@decadentplace.org.uk> wrote in
message news:slrncs37qk.v4b.b...@decadentplace.org.uk...

> Kurt Krueckeberg wrote:
>> Use a CRITICAL_SECTION instead of a mutex. It's faster.
> Win32's CRITICAL_SECTION *is* a mutex.

What do you mean by that?

A Win32 Critical Section is process specific and is documented as
being "slightly faster, more efficient" than Win32 mutexes.

Do you mean that a Win32 CritSec matches some theoretical definition
of a mutex (it certainly is a mutual exclusion device)?
Or are you implying that a Win32 CritSec is implemented in terms of a
Win32 Mutex (in which case one would have to question the documented
claims of being slightly more efficient)?

--
J.T.
Please reply via the newsgroup.

Swampmonster

unread,
Dec 17, 2004, 6:13:33 AM12/17/04
to
> I think clc++m is the wrong group for this discussion also
> because the ISO 14882 implicitly uses a single threaded
> abstract machine. There are some proposals to add multi
> threading into the standard, but AFAICS these are in very
> early stages. See for example

That's funny, because that implies that there can be no standard C++
program that uses multithreading with shared data (I guess mt+sockest
would be ok to use, but... *g*).
Well, I definately hope that multithreadins is "standardized" in one way
or another, and maybe there will sometimes be a nice little namespace
called ::std::threads :-)

Think we can consider this closed.

Thanks,
'monster

ka...@gabi-soft.fr

unread,
Dec 17, 2004, 10:06:09 AM12/17/04
to
Swampmonster wrote:
> ka...@gabi-soft.fr wrote:
> > This has been thrashed out I don't know how many times now.
> > Double checked locking doesn't work in general. (I think it
> > is guaranteed to work with a single processor Intel machine,
> > but that's about the limit of it.)

> Hm. What does the standard say about concurrent read/write of
> builtin types - e.g. a volatile int?

Nothing. The standard defines the observable behavior of a
legal program with no undefined behavior.

It does say that accesses to a volatile object are observable
behavoir, but it clearly states that what constitutes an access
is implementation defined. None of the implementations I know
define it to anything useful.

> Does it say the read _value_ is undefined, and the write
> succeeds anyway (with the int having the correct value after
> that, and no undefined behaviour except the read value of that
> int), or does it say something worse like undefined behaviour
> in general?

Implementation defined. But it doesn't matter here anyway,
since the standard also considers multiple threading undefined
behavior, e.g. the first call to pthread_create means that you
have undefined behavior, and as far as the standard is
concerned, you can forget it.

There are, of course, quality of implementation issues, and if
you are writing multithreaded code, you are concerned not just
with the C++ standard, but also with the Posix standard or the
Windows specification. As far as Posix is concerned, of course,
C++ is undefined behavior:-), so you are at the mercy of what
your compiler implementor decides to define.

In practice, a minimum would require that the C compatible parts
of C++ conform to the Posix C standard (which is slightly
different than the ISO C standard), at least when the
appropriate options are specified. The double locked idiom that
was posted breaks even under this, however; it definitly
violates the multithreaded memory model of Posix. (I've not
been able to find a specification of this for Windows, so until
proof of the contrary, I will suppose that it is more or less
like that of Posix.)

> In the first case it would work anyway, in the second ... well
> then of course anything could happen.

In practice, anything does happen, except sometimes on specific
machines.

As I said, it normally does work on older, single processor
Intel based machines, provided compiler optimization is not
activated.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

ka...@gabi-soft.fr

unread,
Dec 17, 2004, 10:08:48 AM12/17/04
to
Branimir Maksimovic wrote:
> ka...@gabi-soft.fr wrote:
> > Branimir Maksimovic wrote:
> > > Swampmonster wrote:

> <code snip>

> > There is a slight problem with your implementation: it isn't
> > legal C++, and a C++ shouldn't compile it (and some don't).

> Implementations where extern "C" pointer is not same as
> ordinary c++ function pointer would not compile this and
> *that* is pain.

No conforming C++ implementation should compile it. Pain or not.

> > The function you pass
> > to pthread_once must be declared `extern "C"', which means that it
> > cannot be a member, static or otherwise.

> Look at thread about using static member functions as C callbacks.
> I've discovered that this is legal in c++

> extern "C"
> {
> typedef void func_t();
> }

> struct X{
> static func_t func;
> };

> extern"C"
> void X::func()
> {
> }

> compiles with gcc 3.2.2, but not with gcc 2.95.3
> as later compiler complains about different specifications of
> declaration/definition.

It's legal, but it doesn't mean anything: §7.5/4: "A C language
linkage is ignored for the names of class members and the member
function type of class member functions." So while it is legal
to write the above, X::func still has C++ linkage, and its
address cannot be assigned to a pointer to a function with C
linkage.

> > > This is pretty simple and efficient as implementors
> > > of pthread_once can perform all sort of optimisations
> > > for this particular purpose.

> > Can. Does it on your implementation?

> Look at source for pthreads for win32. I didn't look for
> linux, as I was curious about windows pthreads.
>
http://ftp.tw.xemacs.org/pub/sourceware/pthreads-win32/sources/pthreads-snap-2004-11-22/pthread_once.c

The only implementation which interests me is Solaris on Sparc.
For which the sources aren't available.

Given that Posix supports static initialization of Mutex's, it
isn't really an issue. If it were, I'd measure, rather than
look at the sources.

> >(The canonical implementation of pthread_once is:

> > pthread_mutex_lock( &somePreconstructedMutex ) ;
> > if ( ! flag ) {
> > (*userFunction)() ;
> > flag = true ;
> > }
> > pthread_mutex_unlock( &somePreconstructedMutex ) ;

> That would be very bad implementation. If pthread_once should
> use mutex why bother with it after all.

It's clearer. And you get the benefit on platforms which have a
better implementation.

> When testing on linux implementation I don't notice any lock
> contention when using this function. Lot of code relies on
> quality of such functions.

There's obviously got to be some sort of contention resolution.
Whether you notice it or not.

> > > P.S. if posix libs uses c calling convention look at
> > > recent thread about static member functions and extern
> > > "C".

> > Posix libs do use a C calling convention, and any pointers
> > to function passed to them must pass an extern "C" function.

> Yes, you are right, but lot's of implementations of c++ use
> same calling convention as c compiler, and those don't differ
> between c and c++ function pointers.

Even when the implementation uses the same representation, the
code shouldn't compile, according to the C++ standard.

In practice, on my platform (Sun Sparc), it would be absolutely
incredible if they didn't use the same conventions. On an Intel
platform, however, C++ allows a faster calling convention, and
it would be a pretty poor implementation which used the same.
(The last time I actually developped code on an Intel machine,
they did.)

> > On most machines -- maybe even all, you can fudge with a
> > reinterpret_cast, and the code will work anyway.

> Nope. One way reinterpet_cast means this won't work, and if
> works it shouldn't, so better let it be as it is. If code
> compiles, thats fine, but if does not compiles, then extern
> "C" is better solution as reinterpret_cast would lead to
> crash.

Or wrong results -- the difference could be as subtle as the set
of registers which needs to be saved, which could mean that most
of the time, it would work anyway. You're right that you should
verify this in the documentation of the machine before trying
it. However, without the reinterpret_cast, the code simply will
not compile with a conformant C++ compiler -- Sun CC certainly
gives a diagnostic (although the code is guaranteed to work with
the reinterpret_cast).

Anything you do here is implementation dependant, so a
reinterpret_cast is a good sign -- it flags implementation
dependant code.

> > I'd hate to have to defend that code in a code review,
> > though. (On the other hand, it's probably the only way to
> > write a Singleton template.)

> Thanks to this group I've discovered that static member
> functions can be declared as extern "C" through typedef and
> defined accordingly, so template Singleton is still possible.

§14/4: "A template, a template explicit specialization, or a
class template partial specialization shall not have C linkage."
A template class member can be declared with C linkage, but of
course, as I pointed out above, this declaration is ignored.

> Though compiler has to support this, as gcc 2.95.3 ignores
> extern "C" specification, but gcc 3.2.2 does not.

All of the g++ compilers I've tried pretty much ignore linkage,
period, so you can get away with murder. Sun CC complains, but
works with the reinterpret_cast.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

ka...@gabi-soft.fr

unread,
Dec 17, 2004, 11:08:22 AM12/17/04
to
Falk Tannhäuser wrote:
> Randy wrote:
> > ka...@gabi-soft.fr wrote:
> >> There is a slight problem with your implementation: it
> >> isn't legal C++, and a C++ shouldn't compile it (and some
> >> don't). The function you pass to pthread_once must be
> >> declared `extern "C"', which means that it cannot be a
> >> member, static or otherwise.

> > Is the above statement correct? I certainly hesitate before
> > questioning one of your standing, however there was a recent
> > thread in which Francis Glassborow offered the following
> > example for making a static member function have extern "C"
> > linkage:

> > extern "C"
> > {
> > typedef void (f_c)(int);
> > }

> > struct X
> > {
> > static f_c foo;
> > };

> > Does that not work?

To tell the truth, I hadn't even considered that possibility.
So when you mentionned it, I looked it up, and found that:

> No, it doesn't - according to § 7.5/4, the C language linkage is
ignored.

> I'm still looking for an authoritative answer to know if
> template functions can be 'extern "C"' (both Comeau and g++
> think so, but g++ doesn't take into account linkage
> specifications for function pointer types anyway) since I
> couldn't find anything in the Standard on this subject.

I would have thought that the second sentence in §14/4 would
have been conclusive: "A template, a template explicit


specialization, or a class template partial specialization shall

not have C linkage." But I'll be the first to admit that I'm not
really a specialist in templates.

> If it were standard conforming, the following would solve the
> problem:

> extern "C" { typedef void pthread_once_entry_routine(); }
>
> template<void (&fun_ptr)()> pthread_once_entry_routine
extern_C_wrapper; // declaration
> template<void (&fun_ptr)()> void extern_C_wrapper() { fun_ptr(); }
// definition

> ...
> pthread_once(&is_initialised_,
extern_C_wrapper<Singleton::initialize>);

I don't think it's legal.

To be truthful, the situation doesn't occur often enough in my
code for the template solution to be critical. I don't think
I've ever used pthread_once. About the only cases I have are
for starting threads, and that's once in the implementation
Thread, and once in the implementation of DetachedThread (and
the two extern "C" functions are slightly different -- the one
in DetachedThread uses the casted pointer to initialize an
std::auto_ptr).

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

ka...@gabi-soft.fr

unread,
Dec 17, 2004, 11:10:23 AM12/17/04
to
Swampmonster wrote:
> > Boost offers similar functionality for both Posix and
> > Windows. Don't know the details, though.

> Boost (looked it up today, realizing that I had missed some
> parts of the boost::threads lib) uses a named mutex on windoze
> and pthreads otherwise. And one other thing I for one other
> platform - but I don't remember what it was...

The last time I looked at Boost (some time ago), it used a
critical section for boost::mutex, and a Windows mutex for the
other types of mutex, in the Windows implementation.

> >>This is pretty simple and efficient as implementors
> >>of pthread_once can perform all sort of optimisations
> >>for this particular purpose.

> > Can. Does it on your implementation? (The canonical
> > implementation of pthread_once is:

> > pthread_mutex_lock( &somePreconstructedMutex ) ;
> > if ( ! flag ) {
> > (*userFunction)() ;
> > flag = true ;
> > }
> > pthread_mutex_unlock( &somePreconstructedMutex ) ;

> >>P.S. if posix libs uses c calling convention look at recent
> >>thread about static member functions and extern "C".

> > Posix libs do use a C calling convention, and any pointers
> > to function passed to them must pass an extern "C" function.

> Ouch. No exceptions then allowed in the "init_once()" code
> (the "canonical" implementation would deadlock)... but one
> could deal with that.

Well, I should have said: a somewhat simplified version of the
canonical implementation... I suspect that there is more to it
than that, but the point is that some sort of synchronization is
needed, and that on many systems, a mutex is the simplest and
the fastest type of synchronization.

Ideally, of course, such an implementation would only be a
transitional measure. You pop it into libpthreads.so, and you
can offer the functionality before you get around to actually
modifying kernel code to support it directly.

As for exceptions... pthread_once is a C interface. Regardless
of how the function is implemented, leaving the called function
via an exception is undefined behavior. To begin with, you
don't know whether the system will consider that the function
has executed or not. And of course, you have no guarantee that
anything will be cleaned up correctly, or even that the program
won't immediately crash. (pthread_once could use some assembler
code which uses stack frames which are incompatible with the
stack walkback mechanism used in C++.)

> > On most machines -- maybe even all, you can fudge with a
> > reinterpret_cast, and the code will work anyway. I'd hate
> > to have to defend that code in a code review, though.

> Such stuff is exactly what I'm trying to avoid :-)

> > (On the other hand, it's probably the only way to write a
> > Singleton template.)

> I think one could use that 'extern "C"' function to init the
> mutex and return a pointer or store the mutex's address in
> some global.

That's basically what I do. Something along the lines of:

extern "C" Mutex& getMutex() ;
Mutex* ourMutex = &getMutex() ;

extern "C" Mutex&
getMutex()
{
if ( ourMutex == NULL ) {
static Mutex m ;
ourMutex = &m ;
}
return *ourMutex ;
}

The initialization of ourMutex ensures that the function is
called before the start of main, and thus before the start of
threading.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

ka...@gabi-soft.fr

unread,
Dec 17, 2004, 12:32:00 PM12/17/04
to
Branimir Maksimovic wrote:
> ka...@gabi-soft.fr wrote:
> > Branimir Maksimovic wrote:

> > There is a slight problem with your implementation: it isn't
> > legal C++, and a C++ shouldn't compile it (and some don't).

> I checked pthread.h header and you are wrong in this case.

For which system. I tried initializing pthread_once with a C++
function, and I got an error message from Sun CC, on a Sparc.

Posix defines the interface to be C. If there is no extern "C"
on the functions, you cannot call them from C++, at least not
without non-standard compiler magic. If nothing else, C++ will
mangle the names in a manner that they will not be found in the
library. (Unless the library actually provides both a C and a
C++ version. That would be very nice, and presumably, they
would do whatever was necessary in the C++ version to allow
calling functions with C++ linkage. But I've never seen an
implementation which does this.)

Anyway, I can only talk about the systems I have access to.
Both Solaris and Linux wrap all of the declarations in system
headers in an extern "C" { ... } if __cplusplus is defined.
IMHO, C++ would be pretty much unusable on a system which didn't
do this.

> There is no sign of extern "C" in any of function
> declarations. Because this interface works both for c and c++
> that means implementors know what are they doing.

More likely it means that they don't know what they are doing,
and that they don't have access to a conforming C++ compiler (or
don't care about C++) to test.

Another possibility is that they do use extern "C", and that
you missed it, of course. Linux hides it pretty well, for
example:-). Look for something called __BEGIN_DECLS. And to be
frank, no offense meant, but I think that this is the most
likely explination.

> Why isn't legal c++. What is said about pthread_once? if
> particular implementation have identical c and c++ function
> pointers and calling convention, why use extern "C" after all.

Because I can overload pthread_once in C++, so C++ needs to do
something to ensure that the overloaded functions have different
names. And it must know that that the system function has the
same name as it would have in C.

Compiler magic can do the trick, but it is a lot easier to use
extern "C".

> And if implementors put extern "C" in front of declarations,
> code won't compile and that's a good thing. But nobody
> obligates implementors to put extern"C" specifiers if that is
> not necessary. posix specifies c, but both c and c++ can read
> same headers with no problem.

That's because every Posix implementation I've ever seen
conditionally wraps pratically the entire file in an extern
"C". The first lines after the include on Solaris are:

#ifdef __cplusplus
extern "C" {
#endif

and on Linux:

__BEGIN_DECLS

where all of the headers begin by including a file which
contains:

#ifdef __cplusplus
#define __BEGIN_DECLS extern "C" {
#define __END_DECLS }
#else
#define __BEGIN_DECLS /* empty */
#define __END_DECLS /* empty */
#endif

This is one of the very rare cases where I think conditional
compilation is acceptable. (Although even here, I far prefer
the Linux solution, which isolates the condition to one small
segment of a single file).

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Alexander Terekhov

unread,
Dec 17, 2004, 12:33:07 PM12/17/04
to
ka...@gabi-soft.fr wrote:
[...]

> The double locked idiom that was posted breaks even under this,
> however; it definitly violates the multithreaded memory model of
> Posix.

Consider (see .txt referenced below for "class sema" details)

A) DCSI-SEMAS-01

std::auto_ptr<const std::string> expensive;

sema sema_flag(0);
sema sema_lock(1);

const std::string & DCSI_SEMAS() {
// 1st check (sem_getvalue(&m_sem, &return_value))
if (!sema_flag.getvalue()) {
// Lock (ctor: sem_wait(&m_sem), dtor: sem_post(&m_sem)
sema::lock_guard guard(sema_lock);
// 2nd check (sem_getvalue(&m_sem, &return_value))
if (!sema_flag.getvalue()) {
expensive.reset(new std::string("DCSI_SEMAS")); // <init>
sema_flag.post(); // sem_post(&m_sem)
}
}
return *expensive;
}

and

B) DCSI-SEMAS-11

std::auto_ptr<const std::string> expensive;

sema sema_flag(1);
sema sema_lock(1);

const std::string & DCSI_SEMAS() {
// 1st check (sem_getvalue(&m_sem, &return_value))
if (sema_flag.getvalue()) {
// Lock (ctor: sem_wait(&m_sem), dtor: sem_post(&m_sem)
sema::lock_guard guard(sema_lock);
// 2nd check (sem_getvalue(&m_sem, &return_value))
if (sema_flag.getvalue()) {
expensive.reset(new std::string("DCSI_SEMAS")); // <init>
sema_flag.wait(); // sem_wait(&m_sem)
}
}
return *expensive;
}

> (I've not been able to find a specification of this for Windows, so
> until proof of the contrary, I will suppose that it is more or less
> like that of Posix.)

Like what of Posix? It turns out that XBD 4.10 is severly busted
(see http://www.opengroup.org/austin/aardvark/latest/xbdbug2.txt).

FWIW (word-tearing/"memory locations" aside for a moment), here's my
latest sketch of XBD 4.10 replacement patch, so to say.

-----
Applications shall ensure that access to any memory location by more
than one thread is restricted such that no thread can read or modify
a memory location while another thread of control may be modifying it.
Applications shall use functions listed below that synchronize thread
execution and ensure that modifications to locations in memory are
ordered with respect to accesses to the same memory locations in other
threads. There is a happens-before inter-thread ordering with respect
to preceding (in program and inter-thread order) modifications of
memory locations in

a thread calling pthreads_create() and accesses to modified memory
locations in the created thread;

a thread calling fork() and accesses to modified memory locations
in the initial thread of the created process;

a terminated thread and accesses to modified memory locations in
another thread in the same process after that thread returns from
pthread_join() joining the terminated thread, or in another thread
in a parent process after that thread returns from wait() or
waitpid() observing terminated status of a child process;

a thread calling sem_post() on a specified semaphore and accesses
to modified memory locations in another thread after that thread
calls sem_wait() or sem_trywait() or sem_timedwait() and
locks the same semaphore unlocked by the calling thread, or
another thread observes the incremented semaphore value of the
same semaphore by calling sem_getvalue();

a thread calling sem_wait() or sem_trywait() or sem_timedwait()
decrementing semaphore value of a specified semaphore and accesses
to modified memory locations in another thread after that thread
observes the decremented semaphore value of the same semaphore
using sem_getvalue();

< XSI IPC semas... >

< realtime signals? sigvalue is a union with pointer... >

a thread calling pthread_spin_unlock() on a specified spin lock
and accesses to modified memory locations in another thread
after that thread calls pthread_spin_lock() or
pthread_spin_trylock() and locks the same spin lock unlocked by
the calling thread;

a thread calling pthread_rwlock_unlock() on a specified read-
write lock releasing a write lock and read accesses to modified
memory locations in another thread after that thread acquires a
read lock using pthread_rwlock_rdlock() or
pthread_rwlock_timedrdlock() or pthread_rwlock_tryrdlock() on
the same read-write lock unlocked by the calling thread;

a thread calling pthread_rwlock_unlock() on a specified read-
write lock releasing a write lock and read/write accesses to
modified memory locations in another thread after that thread
acquires a write lock using pthread_rwlock_timedwrlock() or
pthread_rwlock_trywrlock() or pthread_rwlock_wrlock() on
the same read-write lock unlocked by the calling thread;

a thread calling pthread_mutex_unlock() on a specified mutex
and accesses to modified memory locations in another thread
after that thread calls pthread_mutex_lock() or
pthread_mutex_timedlock() or pthread_mutex_trylock() and locks
the same mutex unlocked by the calling thread or when another
thread locks the same mutex unlocked by the calling thread
and returns from a call to pthread_cond_wait() or
pthread_cond_timedwait();

a thread calling pthread_cond_wait() or pthread_cond_timedwait()
and accesses to modified memory locations in another thread
after that thread calls pthread_mutex_lock() or
pthread_mutex_timedlock() or pthread_mutex_trylock() and locks
the same mutex unlocked by the calling thread or when another
thread locks the same mutex unlocked by the calling thread
and returns from a call to pthread_cond_wait() or
pthread_cond_timedwait();

a thread calling pthread_barrier_wait() on a specified barrier
and accesses to modified memory locations in another thread
after that thread returns from pthread_barrier_wait() call on
the same specified barrier on the same or later barrier cycle;

a thread calling pthread_once() on a specified pthread_once_t
object returning from a specified init_routine and accesses to
modified memory locations in another thread after that thread
returns from pthread_once() on the same pthread_once_t object.

Functions listed above and also pthread_cond_signal() and
pthread_cond_broadcast() are all side effects.

Conforming applications are said to be data race-free.
-----

regards,
alexander.

--
"Other courts have reached the same conclusion: software is sold
and not licensed."
-- UNITED STATES DISTRICT COURT
CENTRAL DISTRICT OF CALIFORNIA

ka...@gabi-soft.fr

unread,
Dec 17, 2004, 12:35:02 PM12/17/04
to
Allan W wrote:
> This is more complicated than you need.

> Call get_instance() once from main(), before you create any
> threads. This will cause the singleton to be created before
> any threads have started. No mutex needed, works 100% of the
> time.

Declare a static variable and call get_instance() in the
function you use to initialize it, and it will cause the
singleton to be created before you even enter main.

Of course, if someone gets smarty-alec, and starts a few threads
from the initializer of one of their static variables...
Personally, I think it acceptable to just forbid that, but you
do have to document the limitation.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Branimir Maksimovic

unread,
Dec 18, 2004, 7:24:13 AM12/18/04
to

> Another possibility is that they do use extern "C", and that
> you missed it, of course. Linux hides it pretty well, for
> example:-). Look for something called __BEGIN_DECLS. And to be
> frank, no offense meant, but I think that this is the most
> likely explination.

:)

In addition to that I've just found that gcc implicitely
counts everything in system headers to be extern "C" { ... }
When one doesn't want such behavior it must define
NO_IMPLICIT_EXTERN_C macro. This is safeguard for systems
that are not c++ friendly :)

Greetings, Bane.

Branimir Maksimovic

unread,
Dec 18, 2004, 7:24:42 AM12/18/04
to

ka...@gabi-soft.fr wrote:
> Branimir Maksimovic wrote:
> > ka...@gabi-soft.fr wrote:
> > > Branimir Maksimovic wrote:
> > > > Swampmonster wrote:
>
> > <code snip>
>
> > > There is a slight problem with your implementation: it isn't
> > > legal C++, and a C++ shouldn't compile it (and some don't).
>
> > Implementations where extern "C" pointer is not same as
> > ordinary c++ function pointer would not compile this and
> > *that* is pain.
>
> No conforming C++ implementation should compile it. Pain or not.

That's true, but there are no 100% conforming c++ compilers in
existence.
This extern "C" thing doesn't do anything usefull but
to tell compiler not to mangle c++ function names,
so that c can link with c++ libs.

>
> > > The function you pass
> > > to pthread_once must be declared `extern "C"', which means that
it
> > > cannot be a member, static or otherwise.

Unfortunatelly true.

> > When testing on linux implementation I don't notice any lock
> > contention when using this function. Lot of code relies on
> > quality of such functions.
>
> There's obviously got to be some sort of contention resolution.
> Whether you notice it or not.

There is no lock contention.
code is something like this
if(var == DONE)
{
READ_MEMORY_BARRIER();
return 0;
}

>
> > > Posix libs do use a C calling convention, and any pointers
> > > to function passed to them must pass an extern "C" function.
>
> > Yes, you are right, but lot's of implementations of c++ use
> > same calling convention as c compiler, and those don't differ
> > between c and c++ function pointers.
>
> Even when the implementation uses the same representation, the
> code shouldn't compile, according to the C++ standard.

Well, I hope they will change that, as extern "C" does not really
offers any kind of protection.

>
> In practice, on my platform (Sun Sparc), it would be absolutely
> incredible if they didn't use the same conventions. On an Intel
> platform, however, C++ allows a faster calling convention, and
> it would be a pretty poor implementation which used the same.
> (The last time I actually developped code on an Intel machine,
> they did.)

Heh, gcc has switch -mregparm=number_of_registers_to_use
and it works on sparcs, x86, etc.
Guess what, extern "C" or reinterpret_cast wan't save you if you pass
function
compiled with this switch as callback to pthread_create
for example.

> Anything you do here is implementation dependant, so a
> reinterpret_cast is a good sign -- it flags implementation
> dependant code.

It's ugly and really unecessary in this case.
You have to do that just to make code to compile.
Fact is, that neither extern "C" or reinterpret_cast
would work if your functions use different caling convention
then those in libraries.

> > Though compiler has to support this, as gcc 2.95.3 ignores
> > extern "C" specification, but gcc 3.2.2 does not.
>
> All of the g++ compilers I've tried pretty much ignore linkage,
> period, so you can get away with murder. Sun CC complains, but
> works with the reinterpret_cast.

That's unfortunate, but I guess that standard will allow
extern "C" static members and (hopefully) template functions
in next revision.

Greetings, Bane.

Ben Hutchings

unread,
Dec 19, 2004, 7:41:26 PM12/19/04
to
James Talbut wrote:
> "Ben Hutchings" <ben-publ...@decadentplace.org.uk> wrote in
> message news:slrncs37qk.v4b.b...@decadentplace.org.uk...
>> Kurt Krueckeberg wrote:
>>> Use a CRITICAL_SECTION instead of a mutex. It's faster.
>> Win32's CRITICAL_SECTION *is* a mutex.
>
> What do you mean by that?
>
> A Win32 Critical Section is process specific and is documented as
> being "slightly faster, more efficient" than Win32 mutexes.
>
> Do you mean that a Win32 CritSec matches some theoretical definition
> of a mutex (it certainly is a mutual exclusion device)?
<snip>

Exactly. It isn't a critical section - that means a region of code!
I don't disagree that it's more lightweight than a "Win32 mutex"
created by CreateMutex though.

--
Ben Hutchings
Kids! Bringing about Armageddon can be dangerous. Do not attempt it in
your own home. - Terry Pratchett and Neil Gaiman, `Good Omens'

ka...@gabi-soft.fr

unread,
Dec 21, 2004, 5:36:20 AM12/21/04
to
Branimir Maksimovic wrote:
> ka...@gabi-soft.fr wrote:
> > Branimir Maksimovic wrote:
> > > ka...@gabi-soft.fr wrote:
> > > > Branimir Maksimovic wrote:
> > > > > Swampmonster wrote:

> > > <code snip>

> > > > There is a slight problem with your implementation: it isn't
> > > > legal C++, and a C++ shouldn't compile it (and some don't).

> > > Implementations where extern "C" pointer is not same as ordinary
> > > c++ function pointer would not compile this and *that* is pain.

> > No conforming C++ implementation should compile it. Pain or not.

> That's true, but there are no 100% conforming c++ compilers in
> existence.

That's true, too. But there are existing C++ compilers which won't
compile it, for good reason.

> This extern "C" thing doesn't do anything usefull but
> to tell compiler not to mangle c++ function names,
> so that c can link with c++ libs.

That's true on a Sun Sparc. It isn't necessarily true everywhere. It
wasn't true for the MS-DOS compilers I'used, for example, and
presumably, wouldn't be true for good Intel compilers today -- on an
Intel architecture, there are very strong arguments for using a
different calling convention for C and for C++.

> > > > The function you pass to pthread_once must be declared `extern
> > > > "C"', which means that it cannot be a member, static or
> > > > otherwise.

> Unfortunatelly true.

> > > When testing on linux implementation I don't notice any lock
> > > contention when using this function. Lot of code relies on
> > > quality of such functions.

> > There's obviously got to be some sort of contention resolution.
> > Whether you notice it or not.

> There is no lock contention. code is something like this

> if(var == DONE)
> {
> READ_MEMORY_BARRIER();
> return 0;
> }

I'd have to see it in context.

If I remember correctly, we were talking about the implementation of
pthread_once. There *must* be lock contention somewhere in the
implementation, because if two threads arrive at the same time, one
must
wait.

(I'm also a bit dubious about that var == DONE. Presumably, var can be
written by one thread, and read by another. So what's protecting it.)

> > > > Posix libs do use a C calling convention, and any pointers to
> > > > function passed to them must pass an extern "C" function.

> > > Yes, you are right, but lot's of implementations of c++ use same
> > > calling convention as c compiler, and those don't differ between
c
> > > and c++ function pointers.

> > Even when the implementation uses the same representation, the code
> > shouldn't compile, according to the C++ standard.

> Well, I hope they will change that, as extern "C" does not really
> offers any kind of protection.

It's part of the type system. For a reason. Just as passing an int
without converting it to a function which takes a double, calling a C
function using C++ calling conventions is a sure source of error.

> > In practice, on my platform (Sun Sparc), it would be absolutely
> > incredible if they didn't use the same conventions. On an Intel
> > platform, however, C++ allows a faster calling convention, and it
> > would be a pretty poor implementation which used the same. (The
> > last time I actually developped code on an Intel machine, they
did.)

> Heh, gcc has switch -mregparm=number_of_registers_to_use and it works
> on sparcs, x86, etc. Guess what, extern "C" or reinterpret_cast
wan't
> save you if you pass function compiled with this switch as callback
to
> pthread_create for example.

And VC++ has a number of different calling conventions as well. If you
want to shoot yourself in the foot, most compilers are more than happy
to oblige.

So what's your point -- that we shouldn't use these options? Or that
the compiler vendors are evil to provide them? (I presume that in both
cases, they are there to handle special cases, and it is NOT expected
that a "pure" C++ program will need them.)

> > Anything you do here is implementation dependant, so a
> > reinterpret_cast is a good sign -- it flags implementation
dependant
> > code.

> It's ugly and really unecessary in this case. You have to do that
> just to make code to compile. Fact is, that neither extern "C" or

> reinterpret_cast would work if your functions use different calling


> convention then those in libraries.

If you are calling a Posix function (or any other function defined in
an
ABI defined in C), extern "C" had sure better work.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Branimir Maksimovic

unread,
Dec 21, 2004, 9:55:37 PM12/21/04
to

ka...@gabi-soft.fr wrote:
> > > There's obviously got to be some sort of contention resolution.
> > > Whether you notice it or not.
>
> > There is no lock contention. code is something like this
>
> > if(var == DONE)
> > {
> > READ_MEMORY_BARRIER();
> > return 0;
> > }
>
> I'd have to see it in context.

That's code and there is no lock;mutex is used after that.

>
> If I remember correctly, we were talking about the implementation of
> pthread_once. There *must* be lock contention somewhere in the
> implementation, because if two threads arrive at the same time, one
> must
> wait.

Of course, but only during initialization.

>
> (I'm also a bit dubious about that var == DONE. Presumably, var can
be
> written by one thread, and read by another. So what's protecting
it.)

Nothing, and that works with multiple CPU's :).
I use pthread_once for thread local storage initialization
and yet have to see it crash.
Perhaps I should perform extensive stress test of creating
canceling and terminating threads on multiple CPU
machine in order to get it crash.
mysql uses pthread_once to initialize tls, too, someone
would notice if that doesn't work.

> And VC++ has a number of different calling conventions as well. If
you
> want to shoot yourself in the foot, most compilers are more than
happy
> to oblige.
>
> So what's your point -- that we shouldn't use these options?

No. Point is if I declare/define function to be extern "C"
someone can still compile code with this switch and extern "C" want
prevent code to crash.

>
> > > Anything you do here is implementation dependant, so a
> > > reinterpret_cast is a good sign -- it flags implementation
> dependant
> > > code.
>
> > It's ugly and really unecessary in this case. You have to do that
> > just to make code to compile. Fact is, that neither extern "C" or
> > reinterpret_cast would work if your functions use different calling
> > convention then those in libraries.
>
> If you are calling a Posix function (or any other function defined in
> an
> ABI defined in C), extern "C" had sure better work.

I hope so, but is this real case?
Either extern "C" is unecessary or,
(for example on windows) is completelly useless,
because one must use compiler specific extensions.
eg: __cdecl, __stdcall, __fastcall, dllexport and such,
I don't remember more as last time I've programmed
for windows was 1999.

Greetings, Bane.

James Talbut

unread,
Dec 21, 2004, 9:54:04 PM12/21/04
to
"Ben Hutchings" <ben-publ...@decadentplace.org.uk> wrote in
message news:slrncsaq7i.h2i.b...@decadentplace.org.uk...

> James Talbut wrote:
>> Do you mean that a Win32 CritSec matches some theoretical
>> definition
>> of a mutex (it certainly is a mutual exclusion device)?
> Exactly. It isn't a critical section - that means a region of code!
> I don't disagree that it's more lightweight than a "Win32 mutex"
> created by CreateMutex though.

Not arguing, but where do you get this definition of a critical
section as a region of code from?
The name certainly implies that, but I'm wondering whether there is
some definitive definition of the term somewhere that I am unaware of.

--
J.T.
Please reply via the newsgroup.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

ka...@gabi-soft.fr

unread,
Dec 23, 2004, 10:21:36 AM12/23/04
to
Branimir Maksimovic wrote:
> ka...@gabi-soft.fr wrote:
> > > > There's obviously got to be some sort of contention resolution.
> > > > Whether you notice it or not.

> > > There is no lock contention. code is something like this

> > > if(var == DONE)
> > > {
> > > READ_MEMORY_BARRIER();
> > > return 0;
> > > }

> > I'd have to see it in context.

> That's code and there is no lock;mutex is used after that.

> > If I remember correctly, we were talking about the implementation
of
> > pthread_once. There *must* be lock contention somewhere in the
> > implementation, because if two threads arrive at the same time, one
> > must wait.

> Of course, but only during initialization.

Obviously, but you still need the mechanism. When an arbitrary bit of
code arrives at the pthread_once, it cannot automatically know that
initialization is finished.

> > (I'm also a bit dubious about that var == DONE. Presumably, var
can
> > be written by one thread, and read by another. So what's
protecting
> > it.)

> Nothing, and that works with multiple CPU's :).

If there is nothing protecting it, and no special membar instructions
are being generated, it does NOT work on multiple CPU's, at least not
on
a Sparc, nor an Alpha, nor an Intel IA-64.

> I use pthread_once for thread local storage initialization and yet
> have to see it crash. Perhaps I should perform extensive stress test
> of creating canceling and terminating threads on multiple CPU machine
> in order to get it crash. mysql uses pthread_once to initialize tls,
> too, someone would notice if that doesn't work.

I wouldn't be too sure of it. The window in which it will cause
problems would be very, very small, and would depend a lot on a lot of
other things going on on the machine. I'd bet rather on a crash
waiting
to happen.

> > And VC++ has a number of different calling conventions as well. If
> > you want to shoot yourself in the foot, most compilers are more
than
> > happy to oblige.

> > So what's your point -- that we shouldn't use these options?

> No. Point is if I declare/define function to be extern "C" someone
can
> still compile code with this switch and extern "C" want prevent code
> to crash.

But that's a well known problem. Many compilers also have options to
control packing -- compile different parts of the program with
different
options, and it won't work. And even longer ago: compile part of the
program in model large, and another part in model small...

But what is your point?

> > > > Anything you do here is implementation dependant, so a
> > > > reinterpret_cast is a good sign -- it flags implementation
> > > > dependant code.

> > > It's ugly and really unecessary in this case. You have to do
that
> > > just to make code to compile. Fact is, that neither extern "C"
or
> > > reinterpret_cast would work if your functions use different
> > > calling convention then those in libraries.

> > If you are calling a Posix function (or any other function defined
> > in an ABI defined in C), extern "C" had sure better work.

> I hope so, but is this real case?

Sure. To begin with, without the `extern "C"', you'll get error
messages. And while VC++ has a lot of options concerning calling
conventions, it also has a default mode. I don't know the situation
today, but the last time I developped C++ for a PC, with the Zortech
compiler, the default calling conventions were different for C and for
C++, and you needed `extern "C"'. (That was for 16 bit MS-DOS. But
logically, I would expect the conventions to be different between C and
C++.)

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

dieter...@yahoo.com.au

unread,
Dec 23, 2004, 4:17:08 PM12/23/04
to
Hi James,

Would the solution below also work, whilst now no longer requiring the
sneaky assumption of double initialisation? The only other difference
is now that the destructor does get called atexit() ?

// Definition file ...
class Singleton
{
public:
static Singleton& instance();

private:
Singleton() { /* NOOP */ }
~Singleton() { /* NOOP */ }
};


// Implementation file ...
Singleton& Singleton::instance()
{
static Singleton singleton;
return singleton;
}

namespace
{
Singleton& s = Singleton::instance();
}

Regards,

Dieter Beaven

ka...@gabi-soft.fr

unread,
Dec 24, 2004, 4:27:08 PM12/24/04
to
dieter...@yahoo.com.au wrote:

> Would the solution below also work, whilst now no longer requiring
the
> sneaky assumption of double initialisation?

Sure. Anything that will get instance called during the initialization
of static variables will work. My version avoids any extra variable,
but I'm not sure that that is a feature; the code would be a lot
clearer, I suspect, with an extra variable named, say,
dummyForInitialization.

There is a slight (very slight, hopefully) possibility that a
compiler/linker might notice that dummyForInitialization is never used,
and suppress it. (The standard doesn't allow this behavior, but it
wouldn't be the first time a compiler wasn't 100% conform with the
standard.)

> The only other difference is now that the destructor does get called
> atexit() ?

That's really a separate design issue. Your version could easily be
modified to avoid this, and mine so that the destructor is called at
atexit. My current thinking is that it is better never to call the
destructor, at least on the platforms I'm working on, but this has
changed several times in the past -- not calling the destructor is NOT
portable, and may result in a permanent memory leak at the system level
on some systems, but calling the destructor may cause problems in other
destructors of static objects, if they try to use the singleton.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

dayton

unread,
Dec 31, 2004, 8:20:27 PM12/31/04
to
ka...@gabi-soft.fr wrote:
> if ( ourInstance == NULL ) {
> ourInstance = new Singleton ;

The test here is not thread safe.

The DoubleCheck pattern has been discussed in this newsgroup before. An
article has been written about its bogosity.

C++ does not provide any atomic operations. With hyperthreaded
pipelined processors and deep caches, even an increment operation on a
volatile will not guarantee two threads or processors will see the same
value.

There is a mathematical proof that I hope someone will find, that states
it is impossible to emulate an atomic transaction in software unless you
have control of the clock. For this reason you must use functions that
access the processor's assembly language. All modern processors have
some form of locked instruction or compare-and-swap (CAS). On Windows
you would use the InterlockedCompareAndExchange instruction for the
above test. On SPARC cpus, you need to write your own with the SPARC
CAS instruction. MIPS processors have fantastic compare-swap
instruction sets, including a double pointer swap for implementing
non-blocking deques.

With POSIX you would use the pthread_once_init mechanism to initialize a
singleton. On Windows I'd do something like the following:

class Singleton
{
public:
static Singleton& instance() ;

// ...

private:
static Singleton* ourInstance ;
static long singletonControl;
} ;


...
// This initialization occurs at load time, which we can depend
// upon being single threaded.
long Singleton::singletonControl = 0;

Singleton* Singleton::ourInstance = &Singleton::instance() ;

Singleton&
Singleton::instance()
{
if (InterlockedCompareAndExchange(&singletonControl, 1L, 0L) == 0)
{
ourInstance = new Singleton ;
}
return *ourInstance ;
}


Also, my vote is to register a clean-up function to tidy up your
Singleton at process exit to keep your memory leak trackers quiet.


Glen

James Kanze

unread,
Jan 2, 2005, 4:24:58 AM1/2/05
to
dayton wrote:
> ka...@gabi-soft.fr wrote:

>>if ( ourInstance == NULL ) {
>>ourInstance = new Singleton ;

> The test here is not thread safe.

Did you by any chance read the entire article I posted? The
test is thread safe IF (and it's a big if) ourInstance never
changes value. If you look at the rest of the code, the whole
point of my posting was a technique to ensure that ourInstance
would be initialized (once) with its non-null value before
threads started. And once this is done, the code is thread
safe.

For the rest, all of what you say is quite true and well know to
me. And totally irrelevant, because my code is based on the
guarantee that you can read values from multiple threads as long
as no thread modifies the object. You seem to have missed the
fact that my code ensured that instance() was called at least
once before any threading started. And of course, after the
first call to instance, ourInstance never changes value.

--
James Kanze home: www.gabi-soft.fr


Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

Ben Hutchings

unread,
Jan 3, 2005, 4:42:56 AM1/3/05
to
James Talbut wrote:
> "Ben Hutchings" <ben-publ...@decadentplace.org.uk> wrote in
> message news:slrncsaq7i.h2i.b...@decadentplace.org.uk...
>> James Talbut wrote:
>>> Do you mean that a Win32 CritSec matches some theoretical
>>> definition
>>> of a mutex (it certainly is a mutual exclusion device)?
>> Exactly. It isn't a critical section - that means a region of code!
>> I don't disagree that it's more lightweight than a "Win32 mutex"
>> created by CreateMutex though.
>
> Not arguing, but where do you get this definition of a critical
> section as a region of code from?
> The name certainly implies that, but I'm wondering whether there is
> some definitive definition of the term somewhere that I am unaware of.

FOLDOC says it is "[a] non-re-entrant piece of code that can only be
executed by one process at a time."
<http://foldoc.doc.ic.ac.uk/foldoc/foldoc.cgi?critical+section>

Looking more widely, a Google search for definitions
<http://www.google.co.uk/search?q=define%3Acritical+section> shows
that it is generally understood to be a piece of code. Of the few
results that define it as an object, all but one refer to specific OS
environments rather than to general usage.

--
Ben Hutchings
I'm not a reverse psychological virus. Please don't copy me into your sig.

dayton

unread,
Jan 6, 2005, 4:12:02 AM1/6/05
to
James Kanze wrote:
> dayton wrote:
>
>>ka...@gabi-soft.fr wrote:
>
>
>>>if ( ourInstance == NULL ) {
>>>ourInstance = new Singleton ;
>
>
>>The test here is not thread safe.
>
>
> Did you by any chance read the entire article I posted? The
> test is thread safe IF (and it's a big if) ourInstance never
> changes value. If you look at the rest of the code, the whole
> point of my posting was a technique to ensure that ourInstance
> would be initialized (once) with its non-null value before
> threads started. And once this is done, the code is thread
> safe.

Quite often such code is embedded in dynamically loaded objects or
libraries, which may be loaded from multiple threads simultaneously,
which means initialization code may be run multiple times. Because the
construction of the Singleton probably isn't atomic, the assignment to
ourInstance is probably not atomic. It is also probably a bad idea to
allow multiple threads to run the constructor. Your assumption that
ourInstance never changes value just isn't warranted. This one of the
reasons that the POSIX library provides pthread_once_init(), and why you
must always religiously use thread-safe techniques. You limit the
re-use of your code unnecessarily if you do not make such provisions,
and if you ignore such issues they will come back to bite you at a later
date with a really hard-to-track down bug (I know because the code I
posted came directly from such a bug fix to existing code).

This issue isn't really a C++ language problem, other than C++ makes no
provisions for threaded programming -- but the beauty of C++ is that it
also has no prohibition against multithreaded programming.

Rather than making a library call to achieve thread-safe interlocked
instructions, I propose a new storage modifier (in addition to static
and volatile) that indicates all access to the declared variable are to
be done with interlocked instructions.

Glen Dayton

ka...@gabi-soft.fr

unread,
Jan 8, 2005, 12:40:45 AM1/8/05
to
dayton wrote:
> James Kanze wrote:
> > dayton wrote:

> >>ka...@gabi-soft.fr wrote:

> >>>if ( ourInstance == NULL ) {
> >>>ourInstance = new Singleton ;

> >>The test here is not thread safe.

> > Did you by any chance read the entire article I posted? The
> > test is thread safe IF (and it's a big if) ourInstance never
> > changes value. If you look at the rest of the code, the
> > whole point of my posting was a technique to ensure that
> > ourInstance would be initialized (once) with its non-null
> > value before threads started. And once this is done, the
> > code is thread safe.

> Quite often such code is embedded in dynamically loaded
> objects or libraries, which may be loaded from multiple
> threads simultaneously, which means initialization code may be
> run multiple times.

I presume that the system ensures that the initialization of any
dynamically loaded object occurs in a single thread, that the
load function (dlopen or its equivalent) blocks until such
initialization has terminated, and that everything in the newly
loaded object is visible to the thread which invoked dlopen.
Other threads, of course, cannot access any of these objects
until the loading thread publishes the addresses, and this
publication will necessarily involve calls to synchronizing
functions. So I don't see where there can be a problem.

> Because the construction of the Singleton probably isn't
> atomic, the assignment to ourInstance is probably not atomic.

It isn't. Or at least, correct code can't suppose it is. On
the other hand, the memory in which it is running simply isn't
visible outside the system call to load the library until that
system call returns, and that system call should only return
when the initialization has finished, and both the constructor
AND the assignment to ourInstance are complete.

> It is also probably a bad idea to allow multiple threads to
> run the constructor. Your assumption that ourInstance never
> changes value just isn't warranted.

Could you please show a scenario where it isn't guaranteed by
the Posix standard. (I assume that the guarantees under Windows
are similar, but I'm less familiar with them.)

> This one of the reasons that the POSIX library provides
> pthread_once_init(), and why you must always religiously use
> thread-safe techniques.

You mean pthread_once, of course; there is no pthread_once_init
function. The POSIX standard provides pthread_once for
convenience (since it is easily implemented using
pthread_mutex_t and a boolean), and possibly performance (since
a particular implementation can likely implement it faster using
implementation specific techniques) reasons. It's useful is
specific cases. It could be used here. But since there is a
way of ensuring that the critical code is invoked in a thread
safe environment (i.e. in a context where the memory in question
is only visible to a single thread, and there must be at least
one synchronizing function before any other thread can access
it), why not use it.

> You limit the re-use of your code unnecessarily if you do not
> make such provisions, and if you ignore such issues they will
> come back to bite you at a later date with a really
> hard-to-track down bug (I know because the code I posted came
> directly from such a bug fix to existing code).

The code you posted was directly derived from the code I
posted. I'd be very surprised that the actual code you saw used
&Singleton::instance() to initialize ourInstance.

I'm familiar with the alternative solutions. I've studied this
in rather a lot of detail, as a result of some email discussions
with Scott Meyers. I'm pretty familiar with what is and what is
not guaranteed. And while it is quite possible that I've made a
mistake, I'd like to see where? Could you post a scenario which
shows the error?

> This issue isn't really a C++ language problem, other than C++
> makes no provisions for threaded programming -- but the beauty
> of C++ is that it also has no prohibition against
> multithreaded programming.

It does, sort of. Since the standard doesn't define what
happens when you start another thread, it is undefined
behavior. But of course, the problem is general enough, and
enough compilers provide more or less compatible extensions to
support multi-threading, that I think it remains on topic in
this news group.

> Rather than making a library call to achieve thread-safe
> interlocked instructions, I propose a new storage modifier (in
> addition to static and volatile) that indicates all access to
> the declared variable are to be done with interlocked
> instructions.

I think that the committee is looking into specifying
multithreading. I've seen at least one paper on the subject --
by some of the best experts I know of. So I expect that when
the standard recognizes multi-threading, it will not make a mess
of it as the Java specification did.

Of course, the problem here is somewhat special, because it
involves not only multi-threading, but also the context in which
the initialization of statics takes place. In dynamically
loaded objects. This isn't defined as well as it could be,
since Posix ignores C++, and the C++ standard ignores Posix.
But the fact is that every Posix implementation I know of does
initialize static objects before returning from dlopen. And
that is all that is needed.

--
James Kanze GABI Software http://www.gabi-soft.fr

Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Branimir Maksimovic

unread,
Jan 8, 2005, 12:07:48 PM1/8/05
to

dayton wrote:
> James Kanze wrote:
> > dayton wrote:
> >
> >>ka...@gabi-soft.fr wrote:
> >
> >
> >>>if ( ourInstance == NULL ) {
> >>>ourInstance = new Singleton ;
> >
> >
> >>The test here is not thread safe.
> >
> >
> > Did you by any chance read the entire article I posted? The
> > test is thread safe IF (and it's a big if) ourInstance never
> > changes value. If you look at the rest of the code, the whole
> > point of my posting was a technique to ensure that ourInstance
> > would be initialized (once) with its non-null value before
> > threads started. And once this is done, the code is thread
> > safe.
>
> Quite often such code is embedded in dynamically loaded objects or
> libraries, which may be loaded from multiple threads simultaneously,
> which means initialization code may be run multiple times.

That's not the problem of code, rather it is problem of
implementation. on linux dlopen must be protected by lock
at least was with glibc2.0 but it seems that newest
versions of dynamic linkers/libraries are thread safe,
though I'll always use lock just in case :),
on other platforms perhaps, syscall does provide
synchronization in terms of pthread_once.

Because the
> construction of the Singleton probably isn't atomic, the assignment
to
> ourInstance is probably not atomic.

In order to provide working multi threaded environment
calls to dynamically load libraries *must* be synchronized
by user or by syscall. This is not problem of Kanze's code.


It is also probably a bad idea to
> allow multiple threads to run the constructor.

That's why either one must lock around dlopen or it
is provided by system. Remember, you can write
int dummy = init_function(); in c, too,
and if system doesn't provide safety mechanism
that won't work properly.
Interesting article about loader lock and associated
problems on windows:
http://www.lenholgate.com/archives/000369.html

Greetings, Bane.

0 new messages