在最近的开发项目中,发现如果单例类的构造时间较长(500±50 ms)的话,可能存在其他线程中调用GetInstance()接口时,main函数中的单例类对象初始化还未完成。这种情况下,单例类可能会创建两个。第一个单例类是创建好的,第二个会出现某些异常现象,例如:空指针,未获取到资源等...然后当第二个创建完毕之后,会覆盖掉类中的instance指针,导致后续的GetInstance()接口异常。由于构造时间较长所以多线程中同时申请对象时发生两次甚至多次构造的几率增加。
为了避免这类情况发生,需要考虑多线程中单例类构造过程中的线程安全。
所谓的单例类,不过是C++应用层面抽象出来的一种类的实现方式。
在多线程中实现单例类时,可能导致多个线程申请了不同的类实例,从而指向了不同的内存空间。
因为用户在设计这个单例类的时候并没有考虑多线程申请类实例的情况,仅仅时实现了一个最基础的单例类。
在使用C++单例类设计模式的时候,用户需要评估是否存在多线程申请类实例的使用场景,若存在,需要在申请实例的函数内使用锁机制对申请过程进行保护,这样才能保证线程安全。
private:
static std::mutex mutex_;
public:
static Creat * GetInstance() {
std::lock_guard<std::mutex> lock(mutex_);
...
std::mutex Creat::mutex_; //别忘记类外分配内存
上述加互斥锁的写法已经过时了,下面是C++11优雅写法:
class SingleCreat {
public:
static SingleCreat &GetInstance(); /* 局部静态特性的方式实现单实例 */
private:
SingleCreat(); /* 禁止外部构造 */
~SingleCreat(); /* 禁止外部析构 */
SingleCreat(const SingleCreat &signal); /* 禁止外部复制构造 */
SingleCreat&operator=(const SingleCreat &signal); /* 禁止外部赋值操作 */
};
SingleCreat &SingleCreat::GetInstance() {
static SingleCreat signal;
return signal;
}
SingleCreat::SingleCreat() {
}
SingleCreat::~SingleCreat() {
}