zoukankan      html  css  js  c++  java
  • c++之单例模式

    1 本篇主要讨论下多线程下的单例模式实现:

      首先是 double check 实现方式: 这种模式可以满足多线程环境下,只产生一个实例。

        template<typename T>
        class dclsingleton
        {
            public:
                static T& GetInstance()
                {
                    if(NULL == value_)
                    {
                        MutexGuard mg(mutex_);
                        if (NULL == value_)
                        {
                            value_ = new T;
                        }
                    }
    
                    return *value_;
                }
            protected:
                dclsingleton() { std::cout << "dclsingleton constuctor called" << std::endl; }
                dclsingleton(const dclsingleton &dcl) {}
    
            private:
                static T* value_;
                static Mutex mutex_;
        };

       但是这种实现存在除bug的隐患, 问题就在: value_ = new T; 上。《程序员的自我修养》上指出:

      这样的代码是有问题的,问题的来源在于 cpu 的乱序执行。c++里的new 包含了两步。

      (1)分配内存

      (2)调用构造函数

      所以 value_ = new T;  实际上包含了三步:

      (1)分配内存

      (2)在分配内存的位置上调用构造函数  

      (3)将内存地址赋值给 value_;

      这三步中,(2), (3)两步是可以颠倒的,也就是说,可能出现,先执行(3)这是 value_已经不为NULL, 当出现另一个对GetInstance的并发调用,if 内的 value_ != NULL于是返回,但是还没有调用构造函数。于是使用这个指针的时候,就会导致崩溃。

      这时候需要保证(2), (3)的执行顺序,通常需要加上内存屏障,保证一定保证(2)执行完以后,再执行(3)

      这里我加上了__sync_synchronize(); 后 实现是这样的:

      

           static T& GetInstance()
                {
                    if(NULL == value_)
                    {
                        MutexGuard mg(mutex_);
                        if (NULL == value_)
                        {
                            T* tmp = static_cast<T*>(operator new (sizeof(T)));
                            new (tmp) T();
                            __sync_synchronize();
                            value_ = tmp;
                        }
                    }
    
                    return *value_;
                 }

        这样便可以既保证多线程环境安全,又保证不会出现上面的问题。

    2. 加上内存屏障的示例代码:dcl_single.h

      

    #ifndef __DCL_SINGLE_H
    #define __DCL_SINGLE_H
    
    #include <iostream>
    
    namespace yl
    {
        class Mutex
        {
        public:
            Mutex()
            {
                pthread_mutex_init(&mutex_, NULL);
            }
            ~Mutex()
            {
                pthread_mutex_destroy(&mutex_);
            }
    
        public:
            void Lock()
            {
                pthread_mutex_lock(&mutex_);
            }
            void UnLock()
            {
                pthread_mutex_unlock(&mutex_);
            }
    
        private:
            pthread_mutex_t mutex_;
        };
    
        class MutexGuard
        {
        public:
            MutexGuard(Mutex& m) : mutex_(m)
            {
                mutex_.Lock();
            }
    
            ~MutexGuard()
            {
                mutex_.UnLock();
            }
    
        private:
            Mutex mutex_;
        };
    
        template<typename T>
        class dclsingleton
        {
            public:
                static T& GetInstance()
                {
                    if(NULL == value_)
                    {
                        MutexGuard mg(mutex_);
                        if (NULL == value_)
                        {
                            T* tmp = static_cast<T*>(operator new (sizeof(T)));
                            new (tmp) T();
                            __sync_synchronize();
                            value_ = tmp;
                        }
                    }
    
                    return *value_;
                }
            protected:
                dclsingleton() { std::cout << "dclsingleton constuctor called" << std::endl; }
                dclsingleton(const dclsingleton &dcl) {}
    
            private:
                static T* value_;
                static Mutex mutex_;
        };
    
        template<typename T>
        T* dclsingleton<T>::value_ = NULL;
    
        template<typename T>
        Mutex dclsingleton<T>::mutex_;
    }
    
    
    #endif
    View Code

      singletonTest.cpp

    #include "dcl_single.h"
    #include <iostream>
    
    namespace yl
    {
        class MgrSg : public dclsingleton<MgrSg>
        {
            
        private:
            friend class dclsingleton <MgrSg>;
            MgrSg(){ std::cout << "MgrSg: constructor called" << std::endl; }
            ~MgrSg() { std::cout << "MgrSg: desconstructor called" << std::endl; }
        public:
            void print()
            {
                std::cout << "print called" << std::endl;
            }
        };
    }
    
    int
    main(void)
    {
        using namespace yl;
    
        MgrSg::GetInstance().print();
        return 0;
    }

    3. 还可以用 unix 下的 pthread_once 来实现单例模式:

      

    template <typename T>
            class MySingleton
            {
                public:
                    static T & getInstance()
                    {
                        pthread_once(&ponce_, &MySingleton::init);
                        return *instance;
                    }
    
                protected:
                    MySingleton() {}
                    MySingleton(const MySingleton&) {}
                private:
                    static void init()
                    {
                        instance = new T();
                    }
                private:
                    static pthread_once_t ponce_;
                    static T *instance;
            };
    
        template<typename T>
            pthread_once_t MySingleton<T>::ponce_ = PTHREAD_ONCE_INIT;
    
        template<typename T>
            T *MySingleton<T>::instance = nullptr;
    }

    4.我自己遇到的就是以上两种情况,若是希望了解更全面,可参考下边:

      http://www.cnblogs.com/liyuan989/p/4264889.html

    5. 水平有限,望及时指出错误。谢谢

      

  • 相关阅读:
    oracle的安装与plsql的环境配置
    Working with MSDTC
    soapui-java.lang.Exception Failed to load url
    Oracle 一个owner访问另一个owner的table,不加owner
    Call API relation to TLS 1.2
    Call API HTTP header Authorization: Basic
    VS2008 .csproj cannot be opened.The project type is not supported by this installat
    The changes couldn't be completed.Please reboot your computer and try again.
    Create DB Table View Procedure
    DB Change
  • 原文地址:https://www.cnblogs.com/newbeeyu/p/6885098.html
Copyright © 2011-2022 走看看