Singleton单例模式

模式定义

  保证一个类只能生成一个实例对象。

单线程版本

 1 class Singleton{
 2 private:
 3     // 私有化构造函数和拷贝构造函数
 4     Singleton();
 5     Singleton(const Singleton& other);
 6 public:
 7     // 静态对象指针和静态获取对象指针函数
 8     static Singleton* getInstance();
 9     static Singleton* m_instance;
10 };
11 // 初始化
12 Singleton* Singleton::m_instance=nullptr;
13 
14 //线程非安全版本
15 Singleton* Singleton::getInstance() {
16     if (m_instance == nullptr) {
17         m_instance = new Singleton();
18     }
19     return m_instance;
20 }
21 
22 //线程安全版本,但锁的代价过高
23 Singleton* Singleton::getInstance() {
24     Lock lock;
25     if (m_instance == nullptr) {
26         m_instance = new Singleton();
27     }
28     return m_instance;
29 }

多线程版本

class Singleton{
private:
    // 私有化构造函数和拷贝构造函数
    Singleton();
    Singleton(const Singleton& other);
    mutex  mymutex;  //互斥量
public:
    // 静态对象指针和静态获取对象指针函数
    static Singleton* getInstance();
    static Singleton* m_instance;
};
// 初始化
Singleton* Singleton::m_instance=nullptr;    

线程安全版本,但锁的代价过高

1 //线程安全版本,但锁的代价过高
2 Singleton* Singleton::getInstance() {
3     unique_lock<mutex> mylock(mymutex);
4     if (m_instance == nullptr) {
5         m_instance = new Singleton();
6     }
7     return m_instance;
8 }

双检查锁版本(会出错)

 1 //双检查锁
 2 // 但由于内存读写reorder不安全, 编译器的优化有关
 3 // 在汇编层面m_instance = new Singleton()语句可能的执行顺序是
 4 // 先分配内存地址,再执行构造函数,再赋值给内存,导致第二次检查结果为false,但是这时对象还没创建
 5 Singleton* Singleton::getInstance() {
 6     // 这里的检查,在已经创建了单例对象后,就没有必要加锁
 7     if(m_instance==nullptr){
 8         Lock lock;
 9         // 在检查一次是为了避免两个线程都通过了第一个检查,都会创建的对象的情况
10         if (m_instance == nullptr) {
11             m_instance = new Singleton();
12         }
13     }
14     return m_instance;
15 }

原子操作版本

 1 //C++ 11版本之后的跨平台实现 (volatile)
 2 // 或者使用原子操作
 3 std::atomic<Singleton*> Singleton::m_instance;
 4 std::mutex Singleton::m_mutex;
 5 
 6 Singleton* Singleton::getInstance() {
 7     Singleton* tmp = m_instance.load(std::memory_order_relaxed);
 8     std::atomic_thread_fence(std::memory_order_acquire);//获取内存fence
 9     if (tmp == nullptr) {
10         std::lock_guard<std::mutex> lock(m_mutex);
11         tmp = m_instance.load(std::memory_order_relaxed);
12         if (tmp == nullptr) {
13             tmp = new Singleton;
14             std::atomic_thread_fence(std::memory_order_release);//释放内存fence
15             m_instance.store(tmp, std::memory_order_relaxed);
16         }
17     }
18     return tmp;
19 }

  综上,在多线程中,推荐使用原子操作版。

 

posted @ 2020-07-10 10:34  Chen沉尘  阅读(209)  评论(0编辑  收藏  举报