Skip to content

Instantly share code, notes, and snippets.

@hanji
Created October 21, 2012 19:12
Show Gist options
  • Save hanji/3928128 to your computer and use it in GitHub Desktop.
Save hanji/3928128 to your computer and use it in GitHub Desktop.
Being single is not easy.
// 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