Freestyling on patterns, idioms and semantics…

Icon

vivid hallucinations for bloodthirsty digital vampires

Singleton: a mirage of perfection

There are a very few lucky girls on earth who have had the pleasure to read the great and yet so chemically romantic book “Modern C++ Design: Generic Programming and Design Pattern Applied“. But if you are not one of them, don’t worry: it really does not matter.

In that book there is an entire chapter devoted to present a whirl of singleton patterns that Andrei Alexandrescu gracefully dissects with his fervid insight of the out most boundaries of the C++ language. Andrei presents a unique, portable, policy-based pattern (also implemented in his Loki library) which aims at covering most features required to build a perfect Singleton.

What? A singleton? Uhmkay, let’s rewind the tape.

A Singleton, as wikipedia reports, is a design pattern used to restrict instantiation of a class to one object. The usefulness of this pattern has been largely discussed: some consider the singleton a good pattern while others simply an anti-pattern because of the resource decoupling effect which it leads to.

That said, this essay is not meant to eulogize pros and cons of the singleton (after all it would be just a religious war). Instead some achievements of Anadrei are summarized and a candidate for a C++ implementation of the perfect singleton is discussed from the perspective of the GNU compiler.

In his book Andrei addresses two major issues that affect the popular singleton implementations: The thread-safety and the dead reference problem.

Concerning the thread safety, the singleton pattern is supposed to guarantee the uniqueness of the instance, even among different threads. As a result, if a singleton implementation makes use of the construction-on-the-first-use idiom (which returns a local static instance), a locking mechanism is required to prevent threads from constructing multiple instances at the first concurrent access.

That said, the responsibility to build a unique instance goes to the singleton implementation, while the rest of thread-safe constraints are of course up to the class writer. As corner case you may consider a singleton class with no mutable members that returns a const reference to the unique instance. The critical part of such an implementation is the construction, since the subsequent accesses are not required to be atomic at all (the object is constant).

For this issue Andrei presents two popular patterns: the locking singleton (faulty because of the implicit race condition) and the double-checked locking singletons (Douglas Schmidt) which aims at fixing the former race but that under certain architecture/compiler is still faulty (memory barriers are required to carry out a correct double-checked singleton pattern).

The second issue addressed is the dead reference problem. Basically the problem is related to the order of destruction of dependent singletons. At the program’s exit if a singleton destructor makes use of an already destroyed singleton, an undefined behavior occurs (most probably a segfault).

Andrei presents a couple of patterns that overcome this problem. The first one is the phoenix singleton, a special implementation supposed to re-build the instance on demand at the memory address it had before the destruction. The second one is the singleton with longevity, a design which provides a mechanism to control the order of the singleton destructions (by means of a priority queue).

As final aim all the patterns described in the book are blended into a unique, policy-based singleton: the SingletonHolder. The pattern presented is portable and allows the mix of different features, providing the user with a practical way to express her needs in a single definition.

This is the end of the story, period. But you have an overwhelming wish to undergo with a vivid hallucination, take a breath.

Let’s go about things in an orderly way.

First, the Meyers Singleton is dissected to proof it is a robust pattern if compiled with the GNU g++-4.x. Second, a list of attractive requirements for a perfect singleton is provided. Then, a novel, generic singleton implementation is presented.

Okay, I have to admit it. I have loved the Meyers singleton since the first time I studied it (love at first sight?). Meyers presents a very practical way to carry out a singleton class:

class single
{
    public:
    static single &
    instance()
    {
        static single one;
        return one;
    }

    private:
        single()
        {}
        ~single()
        {}

        single(const single &);
        single &operator=(const single& );
};

The properties of the Meyers singleton are listed below:

  1. The class is not instantiable because both default constructor and destructor are private.
  2. The class is not copy-constructible, nor assignable because both copy constructor and assingment operator are private and not implemented.
  3. It is only possible to get a reference to a single instance (one) by means of the static method instance();
  4. The instance is constructed on demand (the first time the instance method is called) and destructed at the program’s exit, in the reverse relative order of which other static objects (and potentially other singletons) are constructed.

single &ref = single::instance();

This class looks great and indeed it is. But what exactly were the reasons that made Andrei to abandon this implementation?

Basically Andrei left it out because it does not provide a means to control the order destruction. In my experience the dead reference problem is a minor problem because it is not common and shows up only when a singleton depends on another singletons during its descruction.

In my opinion what really matters is instead whether a singleton is supposed to be destructed or not at the program’s exit.

If the singleton is not, then the Meyers’ implementation needs a minor change in the static member: The instance is allocated in the heap by means of the new operator and it will not be automatically destroyed at the program’s exit.

static single &
instance()
{
    static single * one = new one;
    return *one;
}

On the other hand, if the singleton is supposed to be destroyed at the program exit and it depends on other singletons that must be destroyed as well, it is possible to control the order of the destructors by accessing their instances at the beginning of the program in the right reverse order:

single_2::instance();
single_1::instance();

This is sufficient to fix the dead reference problem, which seems to be a minor problem that, all in all, it’s not worth striving for.

The second issue to cope with is the race condition which affects the constructor at the first invocation. Even if the standard does not guarantees anything about this issue, starting from the g++ 4 the initialization of function-scope static variables is thread-safe by default. This means that a singleton pattern that relies on local static variables is automagically made thread safe because the constructor is atomic.

The following snippet proves this concept:

struct poc
{
     poc()
     {
         std::cout << "building..."; std::cout.flush(); sleep(5);
         std::cout << "done\n";
     }

     ~poc()
     {
         std::cout << __PRETTY_FUNCTION__ << std::endl;
     }

     static poc &
     instance()
     {
         static poc one;
         return one;
     }
};

void * thread(void *)
{
     poc &r = poc::instance();
}

int main(int argc, char *argv[])
{
     ...
     pthread_create(&thread_1, NULL, thread, NULL);
     pthread_create(&thread_2, NULL, thread, NULL);
     ...
}

here’s the disassembled code of the static function poc::instance():

(gdb) disassemble 'poc::instance()'
Dump of assembler code for function _ZN3poc8instanceEv:

0x0000000000400cb2 <_ZN3poc8instanceEv+0>:      push   %rbp
0x0000000000400cb3 <_ZN3poc8instanceEv+1>:      mov    %rsp,%rbp
0x0000000000400cb6 <_ZN3poc8instanceEv+4>:      sub    $0x30,%rsp
0x0000000000400cba <_ZN3poc8instanceEv+8>:      mov    $0x601428,%eax
0x0000000000400cbf <_ZN3poc8instanceEv+13>:     movzbl (%rax),%eax
0x0000000000400cc2 <_ZN3poc8instanceEv+16>:     test   %al,%al
0x0000000000400cc4 <_ZN3poc8instanceEv+18>:     jne    0x400d4f <_ZN3poc8instanceEv+157>
0x0000000000400cca <_ZN3poc8instanceEv+24>:     mov    $0x601428,%edi
0x0000000000400ccf <_ZN3poc8instanceEv+29>:     callq  0x400988 <__cxa_guard_acquire@plt>
0x0000000000400cd4 <_ZN3poc8instanceEv+34>:     test   %eax,%eax
0x0000000000400cd6 <_ZN3poc8instanceEv+36>:     setne  %al
0x0000000000400cd9 <_ZN3poc8instanceEv+39>:     test   %al,%al
0x0000000000400cdb <_ZN3poc8instanceEv+41>:     je     0x400d4f <_ZN3poc8instanceEv+157>
0x0000000000400cdd <_ZN3poc8instanceEv+43>:     movb   $0x0,-0x11(%rbp)
0x0000000000400ce1 <_ZN3poc8instanceEv+47>:     mov    $0x601430,%edi
0x0000000000400ce6 <_ZN3poc8instanceEv+52>:     callq  0x400c72
0x0000000000400ceb <_ZN3poc8instanceEv+57>:     movb   $0x1,-0x11(%rbp)
0x0000000000400cef <_ZN3poc8instanceEv+61>:     mov    $0x601428,%edi
0x0000000000400cf4 <_ZN3poc8instanceEv+66>:     callq  0x4009f8 <__cxa_guard_release@plt>
0x0000000000400cf9 <_ZN3poc8instanceEv+71>:     mov    $0x400c48,%edi
0x0000000000400cfe <_ZN3poc8instanceEv+76>:     mov    $0x6012e8,%edx
0x0000000000400d03 <_ZN3poc8instanceEv+81>:     mov    $0x601430,%esi
0x0000000000400d08 <_ZN3poc8instanceEv+86>:     callq  0x4009b8 <__cxa_atexit@plt>
0x0000000000400d0d <_ZN3poc8instanceEv+91>:     jmp    0x400d4f <_ZN3poc8instanceEv+157>
0x0000000000400d0f <_ZN3poc8instanceEv+93>:     mov    %rax,-0x28(%rbp)
0x0000000000400d13 <_ZN3poc8instanceEv+97>:     mov    %rdx,-0x20(%rbp)
0x0000000000400d17 <_ZN3poc8instanceEv+101>:    mov    -0x20(%rbp),%eax
...

The calls __cxa_guard_acquire/__cxa_guard_release are injected by the compiler to make the spell: the construction of static variables/objects is atomic. Yet, the __cxa_atexit function is used to register the destructor for the static object called at the program’s exit (note that it’s also possible to prevent the guard injection by passing the option -fno-threadsafe-statics to g++ at compile time).

Cool. G++ makes the Meyers Singleton robust and thread-safe. It seems to be a perfect candidate for the our singleton, but some features are still missing. Here’s the wish-list:

  • You’d like a generic singleton implemented by means of CRTP pattern:
class single: public more::singleton<single, ... >
{
  • You’d like a generic singleton that enables various flavors: destructible (at the application’s exit) or indestructible:
class single : public more::singleton<single, more::singleton_type, ...>
{
    // or

class single : public more::singleton<single, more::indestructible_singleton_type, ...>
{

  • You’d like a generic singleton that allows to CV-qualify the instance:
class single : public more::singleton<single, const more::singleton_type, ... >  // both cv qualifiers should be enabled
{
  • You’d like a generic singleton that once a class publicly derives from it:
  1. It is not instantiable (*).
  2. It is not copyable, nor copy-constructible.
  3. It inherits the static method instance() returning the CV-qualified reference (simple, const or volatile) of the instance created at the first access.
  • You’d like a generic singleton that allows a non-default constructible class to be a singleton.

The parameters passed to the constructor will make sense only at the first access, and they should be ignored in the subsequent calls. Also it would be nice if it was possible to specify the types of the constructor parameters by means of a TYPELIST:

class single : public more::singleton<single, more::singleton_type, TYPELIST(int)>
 {
    ...
    single(int value)
    : _M_member(value)
    {}
    ....

and somewhere in the code:

single & ref = single::instance(10); // build the instance passing 10
single & ref = single::instance();   // access the instance and take a reference

Such a singleton implementation is available here, and except for the feature marked with (*) possible only with a minor trade-off, its design consists in a mixture of template meta-programming and TR1 type traits.

Just few notes about the necessary trade-off. Since is not possible to obtain a class deriving from a generic base that inherits a static member function supposed to build an instance of it (while the class itself is not to be instantiable), the only way to fulfill this requirement is to add to the class constructor an additional parameter defined private in the base class and only accessible from the static member.

Such additional parameter (base_type::tag) must be passed to the constructor as first argument:

class single : public more::singletonTYPELIST(std::string, int)>
{
    single(base_type::tag, const std::string &s, int n)
    {}
};

That’s all folks. If you are far-seeing you can play with my Singleton and then use it in your projects, but don’t forget to buy me a beer in return.

Advertisements

Filed under: programming, ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: