71

Now that C++11 has multithreading I was wondering what is the correct way to implement lazy initialized singleton without using mutexes(for perf reasons). I came up with this, but tbh Im not really good at writing lockfree code, so Im looking for some better solutions.

// ConsoleApplication1.cpp : Defines the entry point for the console application.
//
# include <atomic>
# include <thread>
# include <string>
# include <iostream>
using namespace std;
class Singleton
{

public:
    Singleton()
    {
    }
static  bool isInitialized()
    {
        return (flag==2);
    }
static  bool initizalize(const string& name_)
    {
        if (flag==2)
            return false;// already initialized
        if (flag==1)
            return false;//somebody else is initializing
        if (flag==0)
        {
            int exp=0;
            int desr=1;
            //bool atomic_compare_exchange_strong(std::atomic<T>* obj, T* exp, T desr)
            bool willInitialize=std::atomic_compare_exchange_strong(&flag, &exp, desr);
            if (! willInitialize)
            {
                //some other thread CASed before us
                std::cout<<"somebody else CASed at aprox same time"<< endl;
                return false;
            }
            else 
            {
                initialize_impl(name_);
                assert(flag==1);
                flag=2;
                return true;
            }
        }
    }
static void clear()
{
    name.clear();
    flag=0;
}
private:
static  void initialize_impl(const string& name_)
{
        name=name_;
}
static  atomic<int> flag;
static  string name;
};
atomic<int> Singleton::flag=0;
string Singleton::name;
void myThreadFunction()
{
    Singleton s;
    bool initializedByMe =s.initizalize("1701");
    if (initializedByMe)
        s.clear();

}
int main()
{
    while (true)
    {
        std::thread t1(myThreadFunction);
        std::thread t2(myThreadFunction);
        t1.join();
        t2.join();
    }
    return 0;
}

Note that clear() is just for testing, real singleton wouldnt have that function.

Xeo
  • 123,374
  • 44
  • 277
  • 381
NoSenseEtAl
  • 23,776
  • 22
  • 102
  • 222

6 Answers6

156

C++11 removes the need for manual locking. Concurrent execution shall wait if a static local variable is already being initialized.

§6.7 [stmt.dcl] p4

If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.

As such, simple have a static function like this:

static Singleton& get() {
  static Singleton instance;
  return instance;
}

This will work all-right in C++11 (as long as the compiler properly implements that part of the standard, of course).


Of course, the real correct answer is to not use a singleton, period.

Thomas Jager
  • 4,242
  • 2
  • 14
  • 28
Xeo
  • 123,374
  • 44
  • 277
  • 381
  • 4
    Of course there are no guarantees that the implementation doesn't use mutices to ensure that behaviour, so the "without mutices for performance reasons" might not be satisfied by this (whether Singleton initialization is the right place to worry about that is debatable of course) – Grizzly Jul 29 '12 at 19:20
  • 4
    @Grizzly: Well, it does not "use ``". ;) – Xeo Jul 29 '12 at 19:21
  • @Grizzly: It might use a mutex, but I would not expect it to lock a mutex on the default path, considering that the variable will be initialized once in the application and read many times (i.e. it might use double-checked locking, for example, or an atomic variable and a spinlock... (the variable holding `uninitialized`, `initialized`, `initializing`)... – David Rodríguez - dribeas Jul 29 '12 at 20:00
  • 1
    The `gcc` compiler already does this. Does anybody know if msvc's compiler has added this to the language yet? – Martin York Jul 29 '12 at 20:44
  • regarding static Singletong instance in get() , is that initialized when program is starting or when the get() function is called ? – NoSenseEtAl Jul 31 '12 at 08:06
  • @NoSenseEtAl: Static local variables are initialized the first time the function is called, it's simply lazy initialization. – Xeo Jul 31 '12 at 11:20
  • tnx, I know global statics are init on startup, so I was confused... either way this is a nice feature of C++11, Im glad I know about it... if I get time over weekend I might go and compare g++4.7 and VS11 for performance(100k calls to get() ). – NoSenseEtAl Jul 31 '12 at 11:53
  • 7
    +1, if only for `Of course, the real correct answer is to not use a singleton, period`... :-) ... – paercebal Sep 07 '12 at 20:58
  • 4
    `"Of course, the real correct answer is to not use a singleton, period."` - I have to disagree, singletons have a purpose, they're overused and misused a lot, but they have a purpose. – Leandros Feb 27 '15 at 14:26
  • 2
    @Leandros And which one would that be? – Shoe Feb 27 '15 at 14:41
  • 2
    @Leandros well, don't leave us hanging there like that. Give us an example from your experience. –  Feb 27 '15 at 14:44
  • If a singleton is lazy constructed/initialized, it should presumably, be lazy-destroyed. Now it sounds like a game of Whack-a-Mole. – Martin James Feb 27 '15 at 14:45
  • I've found singletons to be an evil necessity in some situations, or at least I haven't found an alternative just yet. It's when designing general-purpose libraries where the types depend on some global state. For example, take a general-purpose library that provides interned strings (`InternedString`) which rely on hashing a string to get back an integral. To allow clients to define such things at file scope, we have to ensure global access to the hash table, and ensure it is constructed during CRT initialization _before_ `static const InternedString str = ...;` is initialized. –  Jun 01 '15 at 04:28
  • Ideally I'd like to be able to prevent clients using this `InternedString` from being able to use it to define variables at file scope.. but it ends up being a case I often have to support, as people do it anyway. So that kind of forces me into turning that hash table that these interned strings depend on into a singleton. The only way I can think to avoid that is to hack CRT initialization to ensure that this hash table is constructed before any other variables a client could define at file scope... but that would probably require usage of the library to then override the C runtimes. –  Jun 01 '15 at 04:30
  • Link is somewhat worse than dead, it's been taken over by malware. – Ben Voigt Jul 11 '19 at 06:18
44

For me the best way to implement a singleton using C++11 is:

class Singleton {
 public:
  static Singleton& Instance() {
    // Since it's a static variable, if the class has already been created,
    // it won't be created again.
    // And it **is** thread-safe in C++11.
    static Singleton myInstance;

    // Return a reference to our instance.
    return myInstance;
  }

  // delete copy and move constructors and assign operators
  Singleton(Singleton const&) = delete;             // Copy construct
  Singleton(Singleton&&) = delete;                  // Move construct
  Singleton& operator=(Singleton const&) = delete;  // Copy assign
  Singleton& operator=(Singleton &&) = delete;      // Move assign

  // Any other public methods.

 protected:
  Singleton() {
    // Constructor code goes here.
  }

  ~Singleton() {
    // Destructor code goes here.
  }

 // And any other protected methods.
}
Yang
  • 6,872
  • 7
  • 44
  • 62
GutiMac
  • 2,058
  • 18
  • 26
  • is ~Singleton() in protected area? Is it accessible? – snb Aug 31 '17 at 00:14
  • 3
    `static Singleton myInstance;` should be defined in the implementation not the header. – Jeremy Apr 09 '18 at 20:30
  • Why did make constructor protected instead of private? Derived classes will have access to Singleton class constructor and make another Singleton object. – bigdata2 Apr 09 '20 at 22:04
4

IMHO, the best way to implement singletons is with a "double-check, single-lock" pattern, which you can implement portably in C++ 11: Double-Checked Locking Is Fixed In C++11 This pattern is fast in the already-created case, requiring only a single pointer comparison, and safe in the first-use case.

As mentioned in previous answer, C++ 11 guarantees construction-order safety for static local variables Is local static variable initialization thread-safe in C++11? so you are safe using that pattern. However, Visual Studio 2013 does not yet support it :-( See the "magic statics" row on this page, so if you are using VS2013 you still need to do it yourself.

Unfortunately, nothing is ever simple. The sample code referenced for the pattern above cannot be called from CRT initialization, because the static std::mutex has a constructor, and is thus not guaranteed to be initialized before the first call to get the singleton, if said call is a side-effect of CRT initialization. To get around that, you have to use, not a mutex, but a pointer-to-mutex, which is guaranteed to be zero-initialized before CRT initialization starts. Then you would have to use std::atomic::compare_exchange_strong to create and use the mutex.

I am assuming that the C++ 11 thread-safe local-static-initialization semantics work even when called during CRT initialization.

So if you have the C++ 11 thread-safe local-static-initialization semantics available, use them. If not, you have some work to do, even moreso if you want your singleton to be thread-safe during CRT initialization.

Community
  • 1
  • 1
Wheezil
  • 2,611
  • 1
  • 17
  • 32
3
template<class T> 
class Resource
{
    Resource<T>(const Resource<T>&) = delete;
    Resource<T>& operator=(const Resource<T>&) = delete;
    static unique_ptr<Resource<T>> m_ins;
    static once_flag m_once;
    Resource<T>() = default;

public : 
    virtual ~Resource<T>() = default;
    static Resource<T>& getInstance() {
        std::call_once(m_once, []() {
            m_ins.reset(new Resource<T>);
        });
        return *m_ins.get();
    }
};
irsis
  • 732
  • 1
  • 10
  • 30
Pooja Kuntal
  • 351
  • 1
  • 3
  • 12
  • 1
    One thing I am not clear about. Why do you declare destructor as virtual? How would one inherit from singleton, if the constructor is private? – irsis Jul 10 '19 at 21:55
2

It is hard to read your approach as you are not using the code as intended... that is, the common pattern for a singleton is calling instance() to get the single instance, then use it (also, if you really want a singleton, no constructor should be public).

At any rate, I don't think that your approach is safe, consider that two threads try to acquire the singleton, the first one that gets to update the flag will be the only one initializing, but the initialize function will exit early on the second one, and that thread might proceed to use the singleton before the first thread got around to complete initialization.

The semantics of your initialize are broken. If you try to describe / document the behavior of the function you will have some fun, and will end up describing the implementation rather than a simple operation. Documenting is usually a simple way to double check a design/algorithm: if you end up describing how rather than what, then you should get back to design. In particular, there is no guarantee that after initialize completes the object has actually been initialized (only if the returned value is true, and sometimes if it is false, but not always).

David Rodríguez - dribeas
  • 192,922
  • 20
  • 275
  • 473
  • code is ugly, but please not that initialize returns bool. so caller knows if it initialized or not, if not it can spinlock on isInitialized – NoSenseEtAl Jul 29 '12 at 22:53
2
#pragma once

#include <memory>
#include <mutex>

namespace utils
{

template<typename T>
class Singleton
{
private:
    Singleton<T>(const Singleton<T>&) = delete;
    Singleton<T>& operator = (const Singleton<T>&) = delete;

    Singleton<T>() = default;

    static std::unique_ptr<T> m_instance;
    static std::once_flag m_once;

public:
    virtual ~Singleton<T>() = default;

    static T* getInstance()
    {
        std::call_once(m_once, []() {
            m_instance.reset(new T);
        });
        return m_instance.get();
    }

    template<typename... Args>
    static T* getInstance2nd(Args&& ...args)
    {
        std::call_once(m_once, [&]() {
            m_instance.reset(new T(std::forward<Args>(args)...));
        });
        return m_instance.get();
    }
};

template<typename T> std::unique_ptr<T> Singleton<T>::m_instance;
template<typename T> std::once_flag Singleton<T>::m_once;

}

This version complies to be concurrent free where c++11 standard is not guaranteed to be 100% supported. It offers also a flexible way to instantiate the "owned" instance. Even if the magic static word is enough in c++11 and greater the developer may have the necessity to get much more control over the instance creation.

Michal Turlik
  • 137
  • 1
  • 6