关于C++实现的Singleton收集

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

原文链接: https://www.cnblogs.com/logitechlike/archive/2013/01/18/2866021.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    关于C++实现的Singleton收集

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/75984

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 下午5:15
下一篇 2023年2月9日 下午5:15

相关推荐