单例模式 0、静态函数变量版本 利用C++特性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 template <class T >class SingleTon {public : static T& GetInstance () { static T ins; return ins; } SingleTon (const SingleTon&) = delete ; SingleTon& operator =(const SingleTon&) = delete ; virtual ~SingleTon () {} protected : SingleTon () {} }; class Apple : public SingleTon<Apple> { friend SingleTon<Apple>; public : void show () { cout << __FUNCTION__ << endl; } ~Apple () { cout << __FUNCTION__ << endl; } protected : Apple () {} }; class Orange : public SingleTon<Orange> { friend SingleTon<Orange>; public : ~Orange () { cout << __FUNCTION__ << endl; } void show () { cout << __FUNCTION__ << endl; } protected : Orange () {} }; int main () { Apple::GetInstance ().show (); cout << &Apple::GetInstance () << endl; Apple::GetInstance ().show (); cout << &Apple::GetInstance () << endl; Orange::GetInstance ().show (); Orange::GetInstance ().show (); return 0 ; }
1、普通版本(高并发效率不足)(安全)
在类中添加一个私有静态成员单例实例的指针。
声明一个公有静态构建方法用于获取单例实例的指针。
在静态方法中实现”延迟初始化”。 该方法会在首次被调用时创建一个新对象, 并将其存储在静态成员变量中。 此后该方法每次被调用时都返回该实例。
将类的构造函数设为私有。 类的静态方法仍能调用构造函数, 但是其他对象不能调用。
检查客户端代码, 将对单例的构造函数的调用替换为对其静态构建方法的调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Singleton {protected : Singleton (const string& val) : data (val) {} ~Singleton () {} static Singleton* _instance; static mutex _mutex; string data; public : Singleton (const Singleton& another) = delete ; Singleton& operator =(const Singleton& another) = delete ; static Singleton* getInstance (const string& val) ; void show () { cout << "data: " << data << endl; } }; Singleton* Singleton::_instance = nullptr ; mutex Singleton::_mutex; Singleton* Singleton::getInstance (const string& val) { lock_guard<mutex> lock (_mutex) ; if (_instance == nullptr ) { _instance = new Singleton (val); } return _instance; } int main () { Singleton* a = Singleton::getInstance ("aaa" ); a->show (); Singleton* b = Singleton::getInstance ("bbb" ); b->show (); return 0 ; }
2、双检查锁(有隐患) reorder问题:通常new通常有三步:1、分配一块内存空间;2、执行构造器;3、返回指针; 但是由于编译器有时会进行优化,执行顺序变为132:即分配空间后先返回指针,再执行构造器 这样就会到来危险,比如线程A执行new,132,3执行完;线程B发现m_instance非空返回,然后外部直接用这个指针会出错
1 2 3 4 5 6 7 8 9 10 Singleton* Singleton::getInstance () { if (m_instance==nullptr ){ Lock lock; if (m_instance == nullptr ) { m_instance = new Singleton (); } } return m_instance; }
3、双检查锁(安全) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 std::atomic<Singleton*> Singleton::m_instance; std::mutex Singleton::m_mutex; Singleton* Singleton::getInstance () { Singleton* tmp = m_instance.load (std::memory_order_relaxed); std::atomic_thread_fence (std::memory_order_acquire); if (tmp == nullptr ) { std::lock_guard<std::mutex> lock (m_mutex) ; tmp = m_instance.load (std::memory_order_relaxed); if (tmp == nullptr ) { tmp = new Singleton; std::atomic_thread_fence (std::memory_order_release); m_instance.store (tmp, std::memory_order_relaxed); } } return tmp; }
参考资料