http://www.cppblog.com/Fox/archive/2009/09/22/96898.html
本文同步自游戏人生
以前曾经讨论过Singleton的实现,这次在对照ACE和Boost代码的时候,又重新审视了一下二者对Singleton不同的实现。其间的差别也体现了不同的编程哲学:ACE的实现更加偏重多线程中的安全和效率问题;Boost的实现则偏重于使用语言自身的特性满足Singleton模式的基本需求。
o ACE的实现
Douglas C. Schmidt在Double-Checked Locking: An Optimization Pattern for Efficiently Initializing and Accessing Thread-safe Objects一文中对double-check lock(一般译为双检锁)进行了详细的阐述。
ACE的Singleton使用Adapter模式实现对其他类的适配,使之具有全局唯一的实例。由于C++标准并非明确指定全局静态对象的初始化顺序,ACE使用double-check lock保证线程安全,并使之不受全局静态对象初始化顺序的影响,同时也避免了全局静态实现方式的初始化后不使用的开销。
如果你能够准确的区分以下三种实现的弊端和隐患,对double-check lock也就有了足够的了解。
// -------------------------------------------
class Singleton
{
public:
static Singleton *instance (void)
{
// Constructor of guard acquires
// lock_ automatically.
Guard<Mutex> guard (lock_);
// Only one thread in the
// critical section at a time.
if (instance_ == 0)
instance_ = new Singleton;
return instance_;
// Destructor of guard releases
// lock_ automatically.
}
private:
static Mutex lock_;
static Singleton *instance_;
};// ---------------------------------------------
static Singleton *instance (void)
{
if (instance_ == 0) {
Guard<Mutex> guard (lock_);
// Only come here if instance_
// hasn’t been initialized yet.
instance_ = new Singleton;
}
return instance_;
}// ---------------------------------------------
class Singleton
{
public:
static Singleton *instance (void)
{
// First check
if (instance_ == 0)
{
// Ensure serialization (guard
// constructor acquires lock_).
Guard<Mutex> guard (lock_);
// Double check.
if (instance_ == 0)
instance_ = new Singleton;
}
return instance_;
// guard destructor releases lock_.
}
private:
static Mutex lock_;
static Singleton *instance_;
};
更多详情,见Schmidt老师的原文和ACE_Singleton实现。
o Boost的实现
Boost的Singleton也是线程安全的,而且没有使用锁机制。当然,Boost的Singleton有以下限制(遵从这些限制,可以提高效率):
o The classes below support usage of singletons, including use in program startup/shutdown code, AS LONG AS there is only one thread running before main() begins, and only one thread running after main() exits.
o This class is also limited in that it can only provide singleton usage for classes with default constructors.
// T must be: no-throw default constructible and no-throw destructible
template <typename T>
struct singleton_default
{
private:
struct object_creator
{
// This constructor does nothing more than ensure that instance()
// is called before main() begins, thus creating the static
// T object before multithreading race issues can come up.
object_creator() { singleton_default<T>::instance(); }
inline void do_nothing() const { }
};
static object_creator create_object;singleton_default();
public:
typedef T object_type;// If, at any point (in user code), singleton_default<T>::instance()
// is called, then the following function is instantiated.
static object_type & instance()
{
// This is the object that we return a reference to.
// It is guaranteed to be created before main() begins because of
// the next line.
static object_type obj;// The following line does nothing else than force the instantiation
// of singleton_default<T>::create_object, whose constructor is
// called before main() begins.
create_object.do_nothing();return obj;
}
};
template <typename T>
typename singleton_default<T>::object_creator
singleton_default<T>::create_object;
对于多数Singleton使用,Boost提供的版本完全能够满足需求。为了效率,我们有必要对其使用作出一定的限制。
而在多线程编程中,则有必要使用double-check lock降低频繁加锁带来的开销。
但评论有人说:double-checked locking pattern已经被批驳了
http://www.lajabs.net/2011/03/30/boost%E4%B8%8B%E6%9E%84%E9%80%A0%E7%9A%84%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8%E7%9A%84singleton%E5%88%86%E6%9E%90/
Singleton的线程安全的说法大体分两部分,分别是初始化时对象的构造安全,以及对象方法调用的安全,
这边所说的就是Singleton使用时要确保初始化前是单线程的。
scoped_ptr智能指针以及继承boost::noncopyable很好地保证了对象无法被复制或改变,
Singleton中的instance方法使用boost::call_once为重点,这边保证了对象只会被初始化一次(见init函数),从而实现了线程安全。
关于boost::call_once的使用,查看这里
template <class T>
class Singleton : private boost::noncopyable
{
public:
static T& instance()
{
boost::call_once(init, flag);
return *t;
}
static void init()
{
t.reset(new T());
}
protected:
~Singleton() {}
Singleton() {}
private:
static boost::scoped_ptr <T> t;
static boost::once_flag flag;
};
template <class T> boost::scoped_ptr<T> Singleton<T>::t(0); //初始化
template <class T> boost::once_flag Singleton<T>::flag = BOOST_ONCE_INIT; //定义flag为实现call_once
class MyClass : public Singleton<MyClass>
{
friend class Singleton<MyClass>;
public:
void doSomething()
{
//boost::mutex::scoped_lock lock(mutex_);
std::cout << "doSomething.\n";
}
private:
MyClass(){}
//boost::mutex mutex_;
};
int main(int argc, char* argv[])
{
MyClass::instance().doSomething();
return 0;
}
boost 1.52版本中的实现
// singletons created by this code are guarenteed to be unique
// within the executable or shared library which creates them.
// This is sufficient and in fact ideal for the serialization library.
// The singleton is created when the module is loaded and destroyed
// when the module is unloaded.
// This base class has two functions.
// First it provides a module handle for each singleton indicating
// the executable or shared library in which it was created. This
// turns out to be necessary and sufficient to implement the tables
// used by serialization library.
// Second, it provides a mechanism to detect when a non-const function
// is called after initialization.
// make a singleton to lock/unlock all singletons for alteration.
// The intent is that all singletons created/used by this code
// are to be initialized before main is called. A test program
// can lock all the singletons when main is entereed. This any
// attempt to retieve a mutable instances while locked will
// generate a assertion if compiled for debug.
class singleton_module :
public boost::noncopyable
{
private:
static bool & get_lock(){
static bool lock = false;
return lock;
}
public:
// static const void * get_module_handle(){
// return static_cast<const void *>(get_module_handle);
// }
static void lock(){
get_lock() = true;
}
static void unlock(){
get_lock() = false;
}
static bool is_locked() {
return get_lock();
}
};
namespace detail {
template<class T>
class singleton_wrapper : public T
{
public:
static bool m_is_destroyed;
~singleton_wrapper(){
m_is_destroyed = true;
}
};
template<class T>
bool detail::singleton_wrapper< T >::m_is_destroyed = false;
} // detail
template <class T>
class singleton : public singleton_module
{
private:
BOOST_DLLEXPORT static T & instance;
// include this to provoke instantiation at pre-execution time
static void use(T const &) {}
BOOST_DLLEXPORT static T & get_instance() {
static detail::singleton_wrapper< T > t;
// refer to instance, causing it to be instantiated (and
// initialized at startup on working compilers)
BOOST_ASSERT(! detail::singleton_wrapper< T >::m_is_destroyed);
use(instance);
return static_cast<T &>(t);
}
public:
BOOST_DLLEXPORT static T & get_mutable_instance(){
BOOST_ASSERT(! is_locked());
return get_instance();
}
BOOST_DLLEXPORT static const T & get_const_instance(){
return get_instance();
}
BOOST_DLLEXPORT static bool is_destroyed(){
return detail::singleton_wrapper< T >::m_is_destroyed;
}
};
template<class T>
BOOST_DLLEXPORT T & singleton< T >::instance = singleton< T >::get_instance();