Re: Singleton Pattern
On Apr 20, 8:55 pm, joshuamaur...@gmail.com wrote:
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 EagerInitialize 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.
So put it in anonymous namespace in the implementation file. It
doesn't matter. Except that if you're trying to implement a
generic Singleton; templates can't use anonymous namespace
unless your compiler supports export.
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.
There was a difference when I used that name. In his code (and
in mine), the pointer really was a pointer to the single
existing instance; in my own code, its called ourInstance ("our"
being the prefix I use for static members, or anything shared
between all instances). Before I created the template, it
usually was in anonymous namespace; in the generic
implementation, however, it's a static member variable. But the
purpose of the pointer isn't (only) to ensure initialization
before main; it is the pointer to the single instance, and it is
what the function Singleton::instance() returns.
This technique does depend on a subtle point---the fact that the
pointer is guaranteed to be null before the dynamic
initialization occurs. This is something I've often counted on
in C++, and seems natural to me, but I can understand some
programmers being bothered by the fact that given:
Singleton* Singleton::ourSingleton = Singleton::instance() ;
, there is code which counts of the fact that ourSingleton is
actually first initialized with a null pointer. And if that's
the case, I can easily see spending an extra, boolean variable
(e.g. dummyToForceInitBeforeMain), in addition to the pointer,
in order to make the issue clear, e.g.:
Singleton* Singleton::ourSingleton = NULL ;
bool dummyToForceInitBeforeMain = (Singleton::instance(), true ) ;
It's certainly clearer. (Using the pointer, as I and the
original poster do, is cleverer. One could easily say, too
clever.)
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.
Yes. What I was complaining about in your version was the
unnecessary extra complexity. For the rest, it's pretty much a
standard solution.
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.
Yes, but I was concerned about getting the mutex. Somehow,
you've got to get at least one mutex constructed before
threading starts; otherwise, you're going to encounter race
conditions constructing the mutex. All the above really does is
defer the problem from the singleton to the getSingletonMutex
function.
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),
It is in my case:-). But yes, not everyone can ignore Windows.
-2- you make a conscious design choice that there will be no
threads during dynamic initialization (Not always possible),
You *can* usually impose that there be no threads using your
singletons before main. Usually, not always.
-3- or you have access to the single point of thread creation
(Not always possible).
Again, you *can* usually impose that any thread which uses your
components be started by your threading library. Again,
usually, not always.
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.
You're providing a set of components. You can impose
restrictions on code using those components---in fact, you
almost always have to. In our application, for example, we use
lazy initialization for the master mutex. It will fail if a
thread that uses our components is started before main. But
that's a documented restriction for our components; it doesn't
mean that the third party libraries we link against can't start
threads, and at least one, the Sybase library, does. But of
course, Sybase doesn't use our components.
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.
As I said above, the restriction is "no threads which use your
components". In our case, the Sybase threads are far from
trivial (I think). But as third party software, they obviously
don't use our components.
(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.
For memory, that's usually the case. On the other hand, if the
singleton creates a temporary file...
Of course, there's still the problem of constructing the
mutex.
Which I addressed by making the mutex itself
initialized-on-demand eager-initialized.
Yes. That was my point: you need eager initialization
somewhere.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34