Monday, May 10, 2010

Multi-Threaded Singleton : My understanding

Well, there are two aspects of problems arising in multi-threaded environment, for Singleton classes -

1. While creating the object
2. While accessing the object

Both of them pointing to the same static function - getInstance()

http://www.bombaydigital.com/arenared/2005/10/25/1 has provided a good-decent-detailed discussion. Many Thanks to him/her.

The best solution (if possible) is to create instance when only main thread is executing. So, later, when the binary has multiple threads, the object is already in place.

This is the basic code -
class T
{
public:
static T* instance();
private:
T() {}
~T() {}
static T* smInstance;
static VMutex smMutex;
};
// T.cpp:
T* T::smInstance = NULL;
VMutex T::smMutex;
T* T::instance()
{
VMutexLocker lock(&smMutex);
if (smInstance == NULL)
smInstance = new T();
return smInstance;
}

However, you might notice that we've incurred the overhead of locking every time someone accesses the instance of the singleton. There's a well-known pattern to eliminate this overhead, called the double-checked lock. It takes advantage of the fact that we can (apparently) check for null as a quick test before we even bother with locking. Here's how this would look:

T* T::instance()
{
if (smInstance == NULL)
{
VMutexLocker lock(&smMutex);

if (smInstance == NULL) // double-check
smInstance = new T();
}
return smInstance;
}

But, Here is the core problem: We have no guarantee that T will be fully constructed before the pointer smInstance is assigned. For example, the compiler is within its rights to generate processor instructions that implement the statement in the following order:
1. Allocate a memory block sized for T.
2. Assign the address of the memory block to smInstance
3. Call T's constructor.

Consider then what happens if the other thread performs its unsynchronized null pointer test when we are between steps 2 and 3 of the instantiation statement: It will see a non-null value, and will proceed to return the pointer to the raw memory of the not-yet-constructed object.

No comments:

Post a Comment