Created
October 21, 2012 19:12
-
-
Save hanji/3928128 to your computer and use it in GitHub Desktop.
Being single is not easy.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// double-checked locking singleton was an _incorrect_ model | |
// however, it has great influences, such that: | |
// the Java Memory Model changed in favor of it (since J2SE-1.5); | |
// Visual C++ changed 'volatile' semantics (since Visual C++ 2005). | |
// method 1 uses 'volatile'--VC++ only solution. | |
// method 2 uses 'thread_local'--portable C++11 solution. | |
// [you may opt for a much easier 'pthread_once()' solution on POSIX platforms.] | |
// (c) 2012 Ji Han | |
#include <cstdlib> | |
#include <mutex> | |
class noncopyable { | |
protected: | |
noncopyable() {} | |
~noncopyable() {} | |
private: | |
noncopyable(const noncopyable&); | |
const noncopyable& operator=(const noncopyable&); | |
}; | |
#if 0 | |
//#include <pthread.h> | |
class mutex : noncopyable | |
{ | |
public: | |
mutex() { ::pthread_mutex_init(&mtx_, nullptr); } | |
~mutex() { ::pthread_mutex_destroy(&mtx_); } | |
void lock() { ::pthread_mutex_lock(&mtx_); } | |
bool try_lock() { return ::pthread_mutex_trylock(&mtx_) == 0; } | |
void unlock() { ::pthread_mutex_unlock(&mtx_); } | |
//typedef pthread_mutex_t* native_handle_type; | |
//native_handle_type native_handle() { return &mtx_; } | |
private: | |
pthread_mutex_t mtx_; | |
}; | |
#endif | |
#if 0 | |
/** | |
* double-checked locking singleton for Visual C++ 2005 or later | |
* [N.B: this is _incorrect_ under standard C++ 'volatile' semantics!] | |
* code using 'volatile' for synchronization is almost always wrong. | |
*/ | |
template <typename T> | |
class Singleton : noncopyable | |
{ | |
private: | |
static std::mutex mtx_; | |
static volatile T* pInstance_; | |
static void finalize() { delete pInstance_; } | |
protected: | |
Singleton() {} | |
~Singleton() {} | |
public: | |
static T* getInstance() | |
{ | |
if (pInstance_ == nullptr) { | |
std::lock_guard<std::mutex> lock(mtx_); | |
if (pInstance_ == nullptr) { | |
pInstance_ = new T(); | |
std::atexit(&Singleton<T>::finalize); | |
} | |
} | |
return const_cast<T*>(pInstance_); | |
} | |
}; | |
template<typename T> volatile T* Singleton<T>::pInstance_ = nullptr; | |
template<typename T> std::mutex Singleton<T>::mtx_; | |
#else | |
#define thread_local __declspec(thread) // msvc | |
//#define thread_local __thread // gcc | |
/** | |
* double-checked locking singleton | |
* use thread local storage to resolve memory consistency issue | |
*/ | |
template <typename T> | |
class Singleton : noncopyable | |
{ | |
private: | |
static std::mutex mtx_; | |
static thread_local bool hasInstance_; | |
static T* pInstance_; | |
static void finalize() { delete pInstance_; } | |
protected: | |
Singleton() {} | |
~Singleton() {} | |
public: | |
static T* getInstance() | |
{ | |
if (hasInstance_ == false) { | |
std::lock_guard<std::mutex> lock(mtx_); | |
if (pInstance_ == nullptr) { | |
pInstance_ = new T(); | |
std::atexit(&Singleton<T>::finalize); | |
} | |
hasInstance_ = true; | |
} | |
return pInstance_; | |
} | |
}; | |
template<typename T> std::mutex Singleton<T>::mtx_; | |
template<typename T> thread_local bool Singleton<T>::hasInstance_ = false; | |
template<typename T> T* Singleton<T>::pInstance_ = nullptr; | |
#endif | |
class Mono : public Singleton<Mono> | |
{ | |
friend class Singleton<Mono>; | |
Mono() {} | |
~Mono() {} | |
}; | |
int main(int argc, const char **argv) | |
{ | |
Mono* m = Mono::getInstance(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment