How to implement multithread safe singleton in C++11 without using <mutex>

C++MultithreadingC++11SingletonAtomic

C++ Problem Overview


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.

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

Maybe the easiest way to implement a singleton using C++11 is:

WARNING: Although this works according to the C++11 standard (static initialisers are thread-safe), this is not implemented correctly in Microsoft Visual C++ 2012 (static initialisers are NOT thread-safe). If you are targeting VC2012, then you have to use a different approach, as it does not fully implement the C++11 standard.

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.
}

Solution 3 - C++

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.

Solution 4 - C++

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();
	}
};

Solution 5 - C++

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).

Solution 6 - C++

#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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNoSenseEtAlView Question on Stackoverflow
Solution 1 - C++XeoView Answer on Stackoverflow
Solution 2 - C++GutiMacView Answer on Stackoverflow
Solution 3 - C++WheezilView Answer on Stackoverflow
Solution 4 - C++Pooja KuntalView Answer on Stackoverflow
Solution 5 - C++David Rodríguez - dribeasView Answer on Stackoverflow
Solution 6 - C++Michal TurlikView Answer on Stackoverflow