 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Swampmonster Guest
|
Posted: Tue Dec 14, 2004 8:32 pm Post subject: singleton + multithreading + static initialization |
|
|
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! ]
|
|
| Back to top |
|
 |
Kurt Krueckeberg Guest
|
Posted: Wed Dec 15, 2004 1:38 am Post subject: Re: singleton + multithreading + static initialization |
|
|
">
| Quote: | 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_;
};
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Allan W Guest
|
Posted: Wed Dec 15, 2004 4:45 am Post subject: Re: singleton + multithreading + static initialization |
|
|
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! ]
|
|
| Back to top |
|
 |
Ben Hutchings Guest
|
Posted: Wed Dec 15, 2004 4:46 am Post subject: Re: singleton + multithreading + static initialization |
|
|
Swampmonster wrote:
<snip>
| Quote: | 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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
jtorjo@yahoo.com Guest
|
Posted: Wed Dec 15, 2004 10:47 am Post subject: Re: singleton + multithreading + static initialization |
|
|
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!
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Branimir Maksimovic Guest
|
Posted: Wed Dec 15, 2004 1:07 pm Post subject: Re: singleton + multithreading + static initialization |
|
|
Swampmonster wrote:
| Quote: | 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".
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Vladimir Marko Guest
|
Posted: Wed Dec 15, 2004 4:36 pm Post subject: Re: singleton + multithreading + static initialization |
|
|
[email]jtorjo (AT) yahoo (DOT) com[/email] wrote:
| Quote: | 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.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Wed Dec 15, 2004 6:19 pm Post subject: Re: singleton + multithreading + static initialization |
|
|
Swampmonster wrote:
[Classical initialization problem: protecting the creation of a
mutex...]
| Quote: | 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.
| Quote: | 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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Wed Dec 15, 2004 6:20 pm Post subject: Re: singleton + multithreading + static initialization |
|
|
Kurt Krueckeberg 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.)
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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Wed Dec 15, 2004 6:51 pm Post subject: Re: singleton + multithreading + static initialization |
|
|
Branimir Maksimovic wrote:
| Quote: | 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.
| Quote: | 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.
| Quote: | 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 ) ;
| Quote: | 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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Wed Dec 15, 2004 6:53 pm Post subject: Re: singleton + multithreading + static initialization |
|
|
[email]jtorjo (AT) yahoo (DOT) com[/email] wrote:
| Quote: | 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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Swampmonster Guest
|
Posted: Thu Dec 16, 2004 1:25 pm Post subject: Re: singleton + multithreading + static initialization |
|
|
Vladimir Marko wrote:
| Quote: | 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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Swampmonster Guest
|
Posted: Thu Dec 16, 2004 1:26 pm Post subject: Re: singleton + multithreading + static initialization |
|
|
Allan W wrote:
| Quote: | 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,
'monster
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Branimir Maksimovic Guest
|
Posted: Thu Dec 16, 2004 1:26 pm Post subject: Re: singleton + multithreading + static initialization |
|
|
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
| Quote: | 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>
| Quote: |
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
| Quote: | 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.
| Quote: |
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
| Quote: | (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.
| Quote: |
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.
| Quote: |
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
| Quote: | 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.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Allan W Guest
|
Posted: Thu Dec 16, 2004 1:28 pm Post subject: Re: singleton + multithreading + static initialization |
|
|
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.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|