Re: Singleton Pattern
On Apr 20, 1:23 am, James Kanze <james.ka...@gmail.com> wrote:
On Apr 19, 11:53 pm, joshuamaur...@gmail.com wrote:
Your options are "eager-initialized initialized-on-demand
singleton" or "lazy-initialized initialized-on-demand
singleton". There are several implementations for each,
depending on the threading primitive you want to use.
An example implementation of "eager-initialized
initialized-on-demand singleton" (left as an exercise to
determine which parts go in the header and cpp). (Note that
access to the singleton itself may require a mutex. This just
guarantees a single thread-safe construction.)
class singleton_t {};
singleton_t & getSingleton()
{ static singleton_t * x = 0;
if ( ! x)
x = new singleton_t;
return *x;
}
How is that "eager"? It looks like lazy initialization to me. See my E=
agerInitialize class.
It's eager in that it's initialized in static's dynamic
initialization, before main is started.
/* Eager initialize the singleton to ensure it's created
before main, and thus before there are multiple threads. If
threads are created before main, then it's impossible to do
this safely in C++03.*/
namespace
{ struct EagerInitialize { EagerInitialize() { getSingleton(); } };
EagerInitialize instEagerInit;
}
That's fundamentally the same thing he's doing, except that I've
never seen anyone bother with the extra class.
Indeed. I dislike having a static pointer in the class though. Someone
may mistakenly use it as the authoritative version of the singleton,
when in fact it's just there to ensure initialization before main. I'd
move the pointer out of the class to (unnamed) namespace scope in a
cpp file and give it a better name, a name like yours, such as
dummyToForceInitBeforeMain.
The two
"classical" solutions are usinge the results of instance to
initialize the pointer, and using some other "artificial"
variable, e.g.:
namespace {
bool dummyForInitialization = (Singleton::instance(), true) ;
}
No difference between this and my version, except this is simpler, so
I'll probably start using this myself.
An example implementation of "lazy-initialized
initialized-on-demand singleton" (left as an exercise to
determine which parts go in the header and cpp). (Note that it
contains eager-initialization initialization-on-demand of the
guarding mutex.) (Note that access to the singleton itself may
require a mutex. This just guarantees a single thread-safe
construction.)
//from threading library
class mutex {};
class guard { public: guard(mutex& ); ~guard(); };
mutex & getSingletonMutex()
{ static mutex * x = 0;
if ( ! x)
x = new mutex;
return *x;
}
/* Eager initialize mutex to ensure it's created before main,
and thus before there are multiple threads. If threads are
created before main, then it's impossible to do this safely in
C++03.*/
namespace
{ struct EagerInitialize { EagerInitialize() { getSingletonMutex
(); } };
EagerInitialize instEagerInit;
}
class singleton_t {};
singleton_t & getSingleton()
{ guard g(getSingletonMutex());
static singleton_t * x = 0;
if ( ! x)
x = new singleton_t;
return *x;
}
How does this ensure anything that his code doesn't?
It doesn't. I never said his code was wrong. It does however have lazy
thread-safe initialization, whereas my first example and the OP's
example are eager initialization.
It still
fails if a thread which uses the singleton is started from the
constructor of a static object.
I did specifically note this restriction of my solution several
times.
Under Unix, I frequently use a statically initialize
pthread_mutex_t for this sort of thing; as far as I know,
Windows doesn't have anything similar. Otherwise, you have to
ensure that at least one master mutex is created before
threading starts---if all threads are created by the same C++
threading library, the obvious solution is to use lazy
initialization to create the master mutex in the primitive which
creates the threads. (If all threads are created by primitives
in the library, obviously, when the first call to such a
primitive occurs, there are no other threads.)
Generally, if lazy initialization is used, the variable
controling the singleton will be local to the instance class,
e.g. either:
Singleton&
Singleton::instance()
{
ScopedLock l( mutex ) ;
static Singleton theOneAndOnly ;
return theOneAndOnly ;
}
or (more often, in my experience):
Singleton&
Singleton::instance()
{
ScopedLock l( mutex ) ;
static Singleton* theOneAndOnly = NULL ;
if ( theOneAndOnly == NULL ) {
theOneAndOnly = new Singleton ;
}
return *theOneAndOnly ;
}
Indeed. Some platforms require runtime initialization of mutexes,
-1- so you either program to a particular platform where this isn't a
restriction (Not always possible),
-2- you make a conscious design choice that there will be no threads
during dynamic initialization (Not always possible),
-3- or you have access to the single point of thread creation (Not
always possible).
In my company we have external users of our libraries, so 3 is not an
option. Users have direct access to whatever threading library they
want. Also, in my company, we try to support basically every server
platform there is, making 1 not an option. Thus a portable library
writer is left with 2 and making a big explicit note about this in the
interface doc. In my limited experience, the restriction of no threads
before main (or at least threads which only do trivial things before
main) is an acceptable restriction.
(The first calls the destructor on the singleton object, with
the risk of order of destruction issues. The second never
destroys the singleton object.)
Indeed. I'll let the C++ FAQ handle that one. Suffice to say, don't
destroy when the OS will reclaim resources, i.e. don't destroy if the
process dying makes the leak irrelevant.
Of course, there's still the problem of constructing the mutex.
Which I addressed by making the mutex itself initialized-on-demand
eager-initialized.