Gaffer Docs

Two Useful Singleton Templates

Gaffer uses singleton classes in several places. I'll briefly share with you the code for Gaffer's singleton template classes, which I think might be useful to other projects. These are the Singlegon, and the ThreadSingleton.

Singleton

A singleton wrapper based on Scott Meyer's concept of returning a reference so clients can't delete the instance, and the singleton chapter in Andrei Alexandrescu's excellent treatise, Modern C++ Design. For a full education of why this class is designed as it is, read Andrei's book. An enhancement to the the one presented by Andrei is the addition of the Boost Threading Library locking to make singleton creation thread safe.

// A Meyer's Singleton wrapper
template 
class Singleton
{
public:
    static T & inst()
    {
        static T * obj = 0;
        static boost::mutex mtx;

        if (obj)
            return *obj;
        else
        {
            boost::lock_guard lock(mtx);
            if (!obj) // check one more time in case we locked and some other thread created us.
                obj = new T;
            return *obj;
        }
    }

private:
    Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
    ~Singleton();
};

Thread Singleton

A singleton wrapper that creates a unique object per thread by utilizing thread local storage. I do take a bit of credit for this extension of Andrei's design, as I've not heard of this concept before. Gaffer uses this template whenever one of its Process Manager objects needs its own singleton instance, as each Process Manager is running in a different thread. The Boost Threading Library makes this enhancement very simple to implement.

#include <boost/thread.hpp>

// A wrapper for a singleton unique to the calling thread.  Each
// thread has its own instsance.
template 
class ThreadSingleton
{
public:
    static T & tinst()
    {
        static boost::thread_specific_ptr tobj(cleanup);

        if (tobj.get())
            return *tobj.get();
        else
        {
            // Note, no fear of concurrent calls to this code since 
            // thread_specific_ptr.
            tobj.reset(new T);
            return *tobj.get();
        }
    }

private:
    // thread_specific_ptr will call this when destruction is called for.
    static void cleanup(T* tobj) { delete tobj; }

    ThreadSingleton();
    ThreadSingleton(const ThreadSingleton&);
    ThreadSingleton& operator=(const ThreadSingleton&);
    ~ThreadSingleton();
};