文章目录
- 一、单例模式简介
- 1、什么是单例模式?
- 2、单例模式的要点
- 3、单例模式的优点
- 4、单例模式的应用场景
- 二、pthread_once实现线程安全的单例模式
- 1、pthread_once简介
- 2、pthread_once实现线程安全的单例模式
一、单例模式简介
1、什么是单例模式?
单例模式就是一个类只能被实例化一次 ,更准确的说是只能有一个实例化的对象的类。
2、单例模式的要点
- 单例类只能有一个实例—>单例模式的类只提供私有的构造函数。
- 它必须自行创建这个实例—>类定义中含有一个该类的静态私有对象。
- 它必须自行向整个系统提供提供这个实例—>该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。
// 一个单例模式的简单实现
class CSingleton
{
private:
CSingleton() // 私有构造函数
{
}
static CSingleton *p; // 静态数据成员
public:
static CSingleton* getInstance() // 静态成员函数
{
if(p == NULL) // 判断是否第一次调用
p = new CSingleton(); // 调用构造函数
return p;
}
};
CSingleton* CSingleton::p = NULL;
3、单例模式的优点
- 在内存中只有一个对象,节省内存空间。
- 避免频繁的创建销毁对象,可以提高性能。
- 避免对共享资源的多重占用。
- 可以全局访问。
4、单例模式的应用场景
- 需要频繁实例化然后销毁的对象。
- 创建对象耗时过多或者耗资源过多,但又经常用到的对象。
- 有状态的工具类对象。
- 频繁访问数据库或文件的对象。
- 以及其他要求只有一个对象的场景。
二、pthread_once实现线程安全的单例模式
在单例模式的class设计的时候,常常会看到一种写法:
if(xxx==NULL)
{
LOCK();
if(xxx==NULL)
{
xxx=new XXX();
}
return xxx;
}
这个办法叫做double check locking(缩写为DCL)。在《Linux多线程服务端》一书中,作者提出DCL已经靠不住,并提出了使用pthread_once来实现单例的线程安全。
1、pthread_once简介
#include <pthread.h>
int pthread_once(pthread_once_t *once_control,
void (*init_routine) (void));
在多线程环境中,有些事仅需要执行一次。通常当初始化应用程序时,可以比较容易地将其放在main函数中。但当你写一个库时,就不能在main里面初始化了,你可以用静态初始化,但使用一次初始化(pthread_once)会比较容易些。
在多线程编程环境下,尽管pthread_once()调用会出现在多个线程中,init_routine()函数仅执行一次,究竟在哪个线程中执行是不定的,是由内核调度来决定。
2、pthread_once实现线程安全的单例模式
// singleton.h
template<typename T>
class Singleton : boost::noncopyable
{
public:
static T& instance()
{
pthread_once(&ponce_, &Singleton::init);
return *value_;
}
private:
Singleton();
~Singleton();
static void init()
{
value_ = new T();
}
private:
static pthread_once ponce_;
static T* value_;
};
//注意:必须头文件中定义static变量
template <typename T>
pthread_once_t Singleton<T>::ponce_ = PTHREAD_ONCE_INIT;
template<typename T>
T* Singleton<T>::value_ = NULL;
// 使用方法:
MyClass& mc = Singleton<MyClass>::instance();