How to implement multi-threaded safe singleton in C ++ 11 without using <mutex>

Now that C ++ 11 has multi-threading, I was wondering what is the right way to implement a lazy initialized singleton without using mutexes (for primary reasons). I came up with this, but tbh Im really doesn't write blocking code very well, 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; } 

Please note that clear() is for testing purposes only; the real singleton will not have this function.

+70
c ++ multithreading atomic c ++ 11 singleton
Jul 29 '12 at 18:42
source share
6 answers

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

§6.7 [stmt.dcl] p4

If the control enters an declaration simultaneously during variable initialization, parallel execution should wait for initialization to complete.

Thus, just use the static function as follows:

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

This will work fine in C ++ 11 (of course, if the compiler correctly implements this part of the standard).




Of course, the real right answer is not to use a single period.

+142
Jul 29 '12 at 18:52
source share

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

 class Singleton { public: static Singleton& Instance() { // Since it 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. } 
+37
Jan 07 '16 at 11:03
source share

IMHO, the best way to implement singletones is with a double check pattern, one lock, which you can implement portable in C ++ 11: Double locking is fixed in C ++ 11 This pattern is executed quickly in an already created case, requiring only comparison with a single pointer and safe in the first case.

As mentioned in the previous answer, C ++ 11 guarantees the security of the build order for static local variables. Is a local static variable initialization thread safe in C ++ 11? therefore you are safe using this template. However, Visual Studio 2013 does not yet support it :-( See the line “magic statics” 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 by the template above cannot be called from CRT initialization, since the static std :: mutex has a constructor and, therefore, is not guaranteed to be initialized before the first call to get a singleton if the specified call is a side effect of CRT initialization . To get around that , you need to use not a mutex, but a pointer to a mutex, which is guaranteed to be initialized to zero before CRT initialization begins. Then you will need to use std :: atomic :: compare_exchange_strong to create and use the mutex.

I assume that the semantics of C ++ 11 local static initialization work even when called during CRT initialization.

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

+3
Jan 20 '15 at 16:21
source share

It is hard to read your approach, since you are not using the code as intended ... that is, the common template for singleton calls instance() to get one instance and then use it (also, if you really want a single element, no constructor should be publicly available).

In any case, I do not think your approach is safe, consider that two threads try to get a singleton, the first one that receives the flag update will be the only initializer, but the initialize function will exit from the early start of the second, and this thread can continue to use the singleton until of how the first thread wraps to complete initialization.

The semantics of your initialize broken. If you try to describe / document the behavior of a function, you will like it and it will describe the implementation, not just the operation. Documentation is usually an easy way to double check a design / algorithm: if you end up describing how, or not, then you need to get back to design. In particular, there is no guarantee that after completion of initialize object was actually initialized (only if the return value is true , and sometimes if it is false , but not always).

+2
Jul 29 2018-12-12T00:
source share
 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(); } }; 
+2
May 15 '18 at 9:11
source share
 #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 does not require simultaneous use if the C ++ 11 standard is not guaranteed to be 100% supported. It also offers a flexible way to instantiate a "native" instance. Even if a magic static word is sufficient in C ++ 11 and above, a developer may need much more control over instantiation.

+1
Mar 22 '19 at 9:46
source share



All Articles