玩命加载中 . . .

12-单例模式


单例模式

饿汉模式

类定义的时候就创建,是线程安全的

class Singleton{
private:
    static Singleton* instance;
    Singleton(const Singleton&) {}
    Singleton& operator=(const Singleton&) {}
protected:
    Singleton(){} 
public:
    static Singleton* getInstance() {
        return instance;    
    }
};
Singleton* Singleton::instance = new Singleton();

懒汉模式

第一次用到的时候再创建

  • 单线程

访问的时候先判断一下指针是否为空,空的话再创建,只能用在单线程,多线程是不安全的

class Singleton{
private:
    Singleton();
    Singleton(const Singleton&);
public:
    static Singleton* getInstance();
    static Singleton* m_instance;
};

Singleton* Singleton::m_instance = nullptr;

//线程非安全版本
Singleton* Singleton::getInstance() {
    if (m_instance == nullptr) {
        m_instance = new Singleton();
    }
    return m_instance;
}
  • 多线程

1、一种方法是加锁,但是代价过高,如果对象已经创建,访问的时候其实就不需要锁了

Singleton* Singleton::getInstance() {
    Lock lock;  // 访问前先获取锁,函数结束会自动释放
    if (m_instance == nullptr) {
        m_instance = new Singleton();
    }
    return m_instance;
}

也可以用pthread_mutex_t

class Singleton {
private:
    static pthread_mutex_t mutex;
    static Singleton * instance;
    Singleton() {
        pthread_mutex_init(&mutex, NULL);
    }
    Singleton(const Singleton&) {}
    Singleton& operator=(const Singleton&) {}
public:
    static Singleton* getInstance() {
        pthread_mutex_lock(&mutex);
        if(instance == NULL) {
            instance = new Singleton();
        }
        pthread_mutex_unlock(&mutex);
        return instance;
    }
};
Singleton* Singleton::instance = NULL;
pthread_mutex_t Singleton::mutex;

2、后来又提出双检查锁,但是不安全,因为new包括三个步骤,分配内存,构造对象,返回指针,这三个步骤可能不是按顺序的,有可能先分配内存,然后就返回指针,之后才构造对象,这样当一个线程给m_instance赋值之后,另一个线程直接就拿到m_instance,但此时对象还没构造完成,是不能使用的

//双检查锁,但由于内存读写reorder不安全
Singleton* Singleton::getInstance() {
    if(m_instance == nullptr) { // 如果对象已经创建,就不需要加锁
        Lock lock;
        if (m_instance == nullptr) {
            m_instance = new Singleton();
        }
    }
    return m_instance;
}

3、C++11之后规定了静态局部变量的内存模型,并规定了当一个线程正在初始化一个变量的时候,其他线程必须得等到该初始化完成以后才能访问它

class Singleton {
private:
    Singleton() {}
    Singleton(const Singleton&) {}
    Singleton& operator=(const Singleton&) {}
public:
    static Singleton* getInstance() {
        static Singleton instance;
        return &instance;
    }
};

文章作者: kunpeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kunpeng !
  目录