Introduction

As you design your application framework, you may come across certain framework objects that should enforce only a single instance of itself throughout the application lifetime. These objects can range from a file system, a graphic system, to even a simple application logging utility. The design of the framework object is thus known as applying the Singleton Pattern, and is described in [GOF] as

Ensure a class only has one instance, and provide a global point of access to it.

The definition of a singleton is simple, yet has resulted in a wide variety of implementations. Each of this implementation varies from the simplest of issues like storage of instance, to complex multi-threading.

In this article I will describe the few singleton implementations encountered, and put together a singleton object that resolves all likely issues.

Implications of using The Singleton Pattern

Before we begin, it is best to understand the implications of using The Singleton Pattern; that is, the restrictions and rules we have to follow, as well as the benefits. Describe in [GOF], an object implementing The Singleton Pattern must,

Ensure only one instance of a class, and it must be accessible to clients from a well-known access point. Note that however, the limitations did not imply if it is to be a language imposed limitation, or simply a programmer self-imposed limitation.

Allow clients to use an extended instance of the class without modifying their code. That is, the sole instance should be extensible by subclassing.

Additional, a Singleton should own itself. The client is not required to perform additional steps to create the Singleton. From a client side of view, he is, and always is, a client, and takes no part in creation or destruction of the Singleton object.

At first glance it fulfills the basic requirement of The Singleton Pattern, that is, only a single instance of PrintQueue can exist. Additional, it performs the automatic destruction of itself, since static data are destroyed upon program termination. However, it falls short on the second requirement, the inability to subclass the application, and yet provides the client the new extended version without making changes to the code.

Another area the implementation falls short of is the inability to control the initialization and destruction of the singleton. If, during the application lifespan, that PrintQueue was never used, you have paid for the cost of initializing all of PrintQueue’s static data without using it at all. We should always try to obey the same rule that C++ has always obeyed,

You shouldn’t pay for what you don’t use.

Another reason why we would want to control the destruction of the singleton would be, for example, in the case of a Singleton Logging Utility. Imagine that we have one other static object, that upon destruction when program exits, is required to log certain debugging information. However, the static data required to perform logging, at that point of time, might have already been destroyed. This could crash the application immediately.

So now, let’s move on to a non-static data/function approach and have a look at the another Singleton Pattern implementation, this time proposed by Scott Meyer [Meyers 1996b]

As before, this approach has only managed to fulfill the basic requirement, a single instance, as well as automatic Singleton destruction. However, it does manage to solve the problem of not paying for what we don’t use. Notice that with this implementation, the only instance of PrintQueue is a static instance in Instance(). Meyers explained [Meyers 1996b],

…First, it's important that the single Printer object be static in a function and not in a class. An object that's static in a class is, for all intents and purposes, always constructed (and destructed), even if it's never used. In contrast, an object that's static in a function is created the first time through the function, so if the function is never called, the object is never created. (You do, however, pay for a check each time the function is called to see whether the object needs to be created.)…… We know exactly when a function static is initialized: the first time through the function at the point where the static is defined. The situation with a class static (or, for that matter, a global static, should you be so gauche as to use one) is less well defined. C++ offers certain guarantees regarding the order of initialization of statics within a particular translation unit (i.e., a body of source code that yields a single object file), but it says nothing about the initialization order of static objects in different translation units…

Allowing subclass, a quick hack

A quick hack can be applied to the class above actually, so that we can fulfill the second requirement, subclass of the Singleton and yet not required to change any client code.

By having a pointer to an object that has subclassed PrintQueue, we have managed to allow clients to use an extended version of PrintQueue, yet shield them from the knowledge.

Notice the usage of std::auto_ptr. Since instance is now a pointer, there must be a mean to destroy the object. std::auto_ptr helps us accomplish this, since upon the destruction of std::auto_ptr, the destructor calls delete on the held object pointer if valid. And since instance is a static data, the time of destruction is during program termination.

Although this version of fulfills the basic requirement of The Singleton Pattern, this is far from being complete. This being, the destruction order is still undefined.

Removing std::auto_ptr, using atexit

The atexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to atexit create a register of functions that are executed in last-in, first-out (LIFO) order. The functions passed to atexit cannot take parameters. atexit and _onexit use the heap to hold the register of functions. Thus, the number of functions that can be registered is limited only by heap memory.

Thus, using atexit, we can actually do away with std::auto_ptr totally. The above codes can be rewritten as follows,

With this approach, the destruction time of DerivedPrintQueue is actually well-defined (before it goes out of scope). At any point of time, if the program needs to use the PrintQueue, he only needs to call PrintQueue::Instance() , which will return the extended DerivedPrintQueue instance.

The drawbacks of this approach, however, are that in the case that PrintQueue was never used, we have paid for the price of initialization, as well as PrintQueue::Instance() will still return an invalid object if we attempted to call it in one of our global object’s destructor.

Putting it all together, a basic Singleton Template Class

After reviewing the previous implementations, we should arrive at some conclusions.

In order to allow extending of the singleton class, we should use a pointer to the singleton class instead of a static instance. This also gives us the benefit of not paying the cost of initialization if we’re not using it.

An option should be provided to control the destruction order, or simply destroy a singleton.

At times, we would also like to give simply mark certain objects as singleton, and take the last reviewed approach.

Note that the Destroy function is actually made public. This allows us to destroy the Singleton object explicitly.

However, be warned that that if the Destroy function is public, it holds several implications. Being public, it imposes a restriction that client can not actually maintain a local reference of the Singleton object, and all usage of Singleton must goes through the Singleton::Instance. Because otherwise, the client might actually hold a reference to a destroyed Singleton.

There is, of course, a second issue, which I will bring up in the next section.

This seems to be the best Singleton Pattern implementation we can come up with, or is it?

Resolving the multi-threading issue

In an ideal world, everything would have worked. However, we don’t live in an ideal world. Thus, Murphy’s law, “Everything that can go wrong, will go wrong” should be applied whenever possible. Imagine the following code,

In an ideal world, the first thread would reach // 1 first, then hit // 2, then // 3 before another thread calls Instance.

But remember, we don’t live in an ideal world. What would most likely happen would thus be: first thread calls Instance, reach // 1 first. The if statement would return true, and the first thread enters // 2. At the same time, the OS might have interrupted the execution and pass control to the second thread. The second thread calls Instance, and at this time, the if statement would still return true, and the second thread enters // 2 as well. Then the second thread executes // 2, and proceed on to // 3, and the execution was interrupted again and control returned to the first thread. Then the first thread executes // 2, overwriting the instance the second thread created (memory leakage), and proceeds on to // 3.

Of course, whenever multithreading is introduced, we should always also introduce synchronization measures to ensure the ‘correctness’ state of an application. In this case, a mutex lock should be introduced. (Please refer to your favorite OS programming reference on thread synchronization)

A quick solution would produce codes somewhat akin to the one that follows,

The new solution would result in quick access for threads that accessed Instance when instance_ is valid, and slower access (due to the locks) when instance_ is invalid, but those are really rare and one-time cases.

Remember earlier I mentioned that a public Destroy has another
implication? Ok, imagine this process. Assuming the Singleton has been created,
Thread A calls Singleton::Instance. It tests the instance and finds
it valid, then proceed to the return instance statement. Then Thread B comes
into the scene. It checks that instance is valid, and proceeds to destroy it(regardless
if it's double-checked pattern with a lock or otherwise). After this, control
is returned to Thread A again, which attempts to dereference an invalid Singleton
instance, and return to the client. From this we can deduce that exposing Destroy
for explicit destruction is actually not a viable design decision in
a multi-threading environment.

More on the multi-threading

The Double-Checked Locking mechanism applied seems to be a perfect solution,
except that, in some(or maybe even most) cases, it still do not work3 as expected.
The main reason is because on some systems, the writes to memory can be rearranged,
and not be in chronological order. Due to this rearranging of writes, different
threads might, at times, have a different 'view' of the current memory. A thread
might have made the lock, created the Singleton, unlock, and carried on, while
another thread goes in, and see that the instance is still not created, because
the system had rearranged the writes and is performing the writes, and has yet
to write the new value of the instance_ to the memory yet. Aside
from this, some processors actually maintain locally cached copies of memory,
creating even more problems when you need instant and up to date data.

Other possible solutions are employing up to a Triple-Checked Locking mechanism,
or issue an explicit memory barrier instruction (which forces writes to the
memory and retrieve new copies).

Resolving the dead reference issue

Remember earlier when an example was given with the Singleton Logging Utility? The incident where after the destruction of a Singleton, another class object would still wish to get an instance of the Logging Utility. In such a scenario, what should be the possible response of a singleton? We can identify the following responses, either recreate the instance, or throw an exception.

First, however, support has to be built into the Singleton class so that it can know if a null instance means a dead reference situation, or simply an uninitialized instance. An additional boolean variable is introduced to fill the role. The resulting Instance code might look as follows (remember to add the relevant boolean variable setting to Destroy as well)

History

21th August 2003: More on the multi-threading, as well as updated conclusion.

13th August 2003: Risks of having Destroy and Reset in a multi-threading environment,
as well as definition of Singleton updated.

12th August 2003: Initial version uploaded.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

About the Author

Comments and Discussions

i think that there is a problem with LockThread.
Because, the method Instance() is static but the LockThread is not static.
If two threads call Instance() method, then it will create two LockThread object, so we don't a good mutex... no ?

My idea is to put a mutex as a variable like
static T* instance_;

then
static Mutex m_mutex;

and in the Instance() method, we put
m_mutex.lock()
...
m_mutex.unlock()