本文最后更新于:2020年6月30日 晚上
* 这篇开始总结几个比较常用的设计模式。。。不会设计模式。。怎么敢称熟悉OOP思想。。。→_→ *
单例模式的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例,即一个类只有一个对象实例
版本一:使用懒加载(快加载),只有在使用时才实例化
class Singleton
{
public:
static Singleton* getIntance()
{
if (pobject == NULL)//懒加载,只有在使用时才生成
{
pobject = new Singleton();
}
return pobject;
}
private:
Singleton(){}
static Singleton *pobject;
};
Singleton* Singleton::pobject = NULL;//懒加载,只有在使用时才生成
版本二:考虑多线程安全问题,使用互斥锁
- 判断是否是线程安全的——是否存在竞态条件
- 判断是否存在竞态条件——随着线程调度顺序的不同,代码执行的结果也会不同。
- 存在竞态条件的代码称为临界区,临界区代码需要是原子操作,实现原子操作需要使用互斥锁,if语句不是原子操作
class Singleton { public: static Singleton* getIntance() { pthread_mutex_lock(&mutex);//多线程线程安全问题 if (pobject == NULL)//懒加载,只有在使用时才生成 { pobject = new Singleton(); } pthread_mutex_lock(&mutex); return pobject; } private: Singleton(){} static Singleton *pobject; }; Singleton* Singleton::pobject = NULL;//快加载 懒加载
版本三:由于可能存在单线程或多线程共存的使用场景,降低单线程获取释放锁的效率,使用双重if判断
- 单线程时,只需要执行一次获取释放互斥锁操作,之后第一个if语句都为false
- 多线程时,依旧考虑线程安全与竞态条件问题
class Singleton
{
public:
static Singleton* getIntance()
{
if (pobject == NULL)//懒加载,只有在使用时才生成
{
pthread_mutex_lock(&mutex);//多线程线程安全问题
if (pobject == NULL)//单线程时效率问题
{
pobject = new Singleton();
}
pthread_mutex_lock(&mutex);
}
return pobject;
}
private:
Singleton(){}
static Singleton *pobject;
};
Singleton* Singleton::pobject = NULL;//快加载 懒加载
版本四:考虑编译器的指令优化和CPU的动态指令优化
- volatile关键字阻止编译器为了提高速度将一个变量缓存到寄存器内而不写回内存
- volatile关键字阻止编译器调整操作volatile变量的指令操作
- barrier指令会阻止CPU对指令进行动态换序优化
class Singleton
{
public:
volatile static Singleton* getIntance()
{
if (pobject == NULL)//懒加载,只有在使用时才生成
{
pthread_mutex_lock(&mutex);//多线程线程安全问题
if (pobject == NULL)//单线程时的效率问题
{
Singleton* temp = new Singleton;
barrier();//防止CPU对指令进行动态换序优,使对象的构造一定在barrier完成,因此赋值给pobject的对象是完好的
pobject = temp;
}
pthread_mutex_lock(&mutex);
}
return pobject;
}
private:
Singleton(){}
volatile static Singleton *pobject;
};
volatile Singleton* Singleton::pobject = NULL;//快加载 懒加载
* 码完。。。睡觉!→_→。。。 *
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!