前言
单例模式,故名思义,其意图是保证一个类只有一个实例,并提供一个访问它的全局访问点,该实例被所有的程序模块共享.在很多地方要用到这种设计模式,如系统的日志输出,操作系统的窗口,一个pc连一个键盘等.
单例模式有许多实现方法.
1.懒汉模式
第一次调用该类实例的时候才产生一个新的该类实例,并在以后仅返回此实例,
需要加锁,因为可能会有多个线程进入判断实例是否存在的if语句,从而它是非线程安全的.使用double-check(即两次判断实例是否存在,原因见代码注释.),同时,如果处理大量数据,该锁成为严重的性能瓶颈.
#include<iostream>
#include<mutex>
class Singleton
{
private:
Singleton(){};
// Singleton(const Singleton &);
// Singleton& operator = (const Singleton &);
public:
static Singleton *Instantialize();
static Singleton *pInstance;
static std::mutex mut;
};
Singleton* Singleton::pInstance = NULL; //静态变量要在类外进行初始化或在类外进行声明.
std::mutex Singleton::mut; //在类外声明但不进行初始化.
Singleton * Singleton::Instantialize(){
//用两次的原因:
//1.如果一个线程进入第一个if,加锁,在还没有实例话pInsatnce时,第二个线程进入第一个if,等待锁的释放,第一个线程释放锁后,如果没有第一个if,则会导致第二个线程会再次进行创建.
//
if(pInstance == NULL){
std::lock_guard<std::mutex> locker(mut);
if(pInstance == NULL){
pInstance = new Singleton();
}
}
return pInstance;
}
int main(int argc,char *argv[])
{
Singleton* p1 = Singleton::Instantialize();
Singleton* p2 = Singleton::Instantialize();
std::cout << "p1"<<p1 <<" "<<"p2"<<p2<<std::endl;
return 0;
}
2.内部静态实例的懒汉模式
#include <iostream>
#include <mutex>
#include<stdio.h>
class SingleInside
{
private:
SingleInside(){}
public:
static SingleInside& GetInstance(){
static SingleInside instance;
return instance;
}
};
int main(int argc,char *argv[])
{
SingleInside single = SingleInside::GetInstance();
SingleInside Single1 = SingleInside::GetInstance();
printf("single:%p\nsingle1:%p\n",single,Single1);
return 0;
}
运行结果:
single:0x7ffd1ef69d98
single1:0x7ffd1ef69da8
从结果可以看出,两个实例的地址不同此方法每次调用GetInstance()方法,都会进行实例的拷贝.
3.饿汉模式
即无论是否调用该类的实例,在程序开始时就会产生一个该类的实例,并在以后仅返回此实例。
由静态初始化实例保证其线程安全性,为什么呢?因为静态实例初始化在程序开始时进入主函数之前就由主线程以单线程方式完成了初始化,不必担心多线程问题。
#include<iostream>
class SingletonStatic
{
private:
static const SingletonStatic* m_instance;
SingletonStatic(){}
public:
static const SingletonStatic* getInstance(){
return m_instance;
}
};
const SingletonStatic* SingletonStatic::m_instance = new SingletonStatic;
int main(int argc,char *argv[])
{
const SingletonStatic *p1 = SingletonStatic::getInstance();
const SingletonStatic *p2 = SingletonStatic::getInstance();
std::cout << "p1:"<<p1 <<" "<< "p2:"<<p2<<std::endl;
return 0;
}
运行结果:
p1:0xf07010 p2:0xf07010
4.委托模式
我们知道,程序在结束的时候,系统会自动析构所有的全局变量。事实上,系统也会析构所有的类的静态成员变量,就像这些静态成员也是全局变量一样。利用这个特征,我们可以在单例类中定义一个这样的静态成员变量,而它的唯一工作就是在析构函数中删除单例类的实例.
#include<iostream>
#include <mutex>
class CSingleton
{
private:
CSingleton(){}
static CSingleton* m_pInstance;
static std::mutex mtx;
class GC{
public:
~GC(){ //此类唯一的工作就是在析构函数中删除单例类的实例.
if(CSingleton::m_pInstance){
delete CSingleton::m_pInstance;
}
}
};
static GC gc;
public:
static CSingleton *GetInstance(){
if(m_pInstance == NULL){
std::lock_guard<std::mutex> lock(mtx);
if(m_pInstance == NULL){
m_pInstance = new CSingleton();
}
}
return m_pInstance;
}
};
CSingleton::GC CSingleton::gc;
CSingleton* CSingleton::m_pInstance = NULL;
std::mutex CSingleton::mtx;
int main(int argc,char *argv[])
{
CSingleton *p1 = CSingleton::GetInstance();
CSingleton *p2 = CSingleton::GetInstance();
std::cout << "p1:"<<p1<<" " <<"p2:"<<p2<<std::endl;
return 0;
}
运行结果:
p1:0x911010 p2:0x911010