Thursday 23 October 2014

C++ Correct multi threaded singleton initialisation

Correct double-checked locking pattern

1. Pointer must be atomic
2. Check, lock, check, construct

std::atomic<Foo*> foo { nullptr };

Foo* instance()
{
    Foo* f = foo; // single load of foo
    if (!f)
    {
        std::lock_guard<std::mutex> l(foo_lock);
        if (!foo)
        {
            foo = f = new Foo(); // assign both foo and f
        }
    }
    return f;
}

Even better, use std::unique_ptr and std::once to get automatic cleanup and less scaffolding

class Foo
{
public:
    static Foo& instance()
    {
        std::call_once(_create, [=]{
            _instance = std::make_unique<Foo>();
        });
        return *_instance;
    }

private:
    static std::unique_ptr<Foo> _instance;
    static std::once_flag       _create;
};

Or just use a function local static

Foo& Foo::instance()
{
    static Foo foo;
    return foo;
}

No comments:

Post a Comment