zoukankan      html  css  js  c++  java
  • 关于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();

  • 相关阅读:
    lombok介绍
    idea 离线安装 lombok插件
    Java中Lambda表达式的使用
    接口里的default,static方法
    Maven多环境配置实战 filter
    redis lua脚本学习
    redis的安装
    jdbc插入或查询数据库时间总是比实际时间少8小时原因
    [设计模式]单件模式
    [设计模式]命令模式
  • 原文地址:https://www.cnblogs.com/logitechlike/p/2866021.html
Copyright © 2011-2022 走看看