|
单体模式想必大家都很熟悉, 该模式的设计要点就是构造函数是私有或者保护的, 只能通过一个接口来构造它的一个实例, 从而保证系统范围内只有该类的一个实例对象, 实例如下:
class Singleton
{
public:
static Singleton* instance()
{
if(NULL == m_pInstance)
{
m_pInstance = new Singleton();
}
return m_pInstance;
}
public:
//其他的单体服务接口
private:
Singleton()
{
//初始化操作
}
static Singleton* m_pInstance;
}
但是上面的代码存在问题, 你看出来了吗?
在单线程环境下, 该代码是安全的, 但是移置到多线程环境下, 就会有隐患, 因为m_pInstance是静态成员变量, 在多个线程对它访问时需要同步.
如果多个线程同时调用该类的instance()接口, 就会出现内存泄漏.
我们可以在此增加一个锁成员变量, 来对它进行同步保护.
基于单线程和多线程之间的移植问题, 我们把该锁变量的类型参数化
template <class LOCK>
class Singleton
{
public:
static Singleton* instance()
{
Guard<LOCK> temp(m_lock); //关于Guard请参考我上篇贴
if(NULL == m_pInstance)
{
m_pInstance = new Singleton();
}
return m_pInstance;
}
public:
//其他的单体服务接口
private:
Singleton()
{
//初始化操作
}
static Singleton* m_pInstance;
static LOCK m_lock;
}
这样安全了, 但是效率方面呢? 为了访问这个单体的服务, 每次访问instance()接口都要进行一次锁定操作, 效率大打折扣.
这样我们就要想了, 最好是在第一次初始化的时候需要锁定, 以后就可以直接访问了, 下面是改善后的代码
template <class LOCK>
class Singleton
{
public:
static Singleton* instance()
{
if(NULL == m_pInstance)
{
Guard<LOCK> temp(m_lock); // 关于Guard请参考我上一篇贴
if(NULL == m_pInstance)
{
m_pInstance = new Singleton();
}
}
return m_pInstance;
}
public:
//其他的单体服务接口
private:
Singleton()
{
//初始化操作
}
static Singleton* m_pInstance;
static LOCK m_lock;
}
这样在访问instance的时候就会进行2次检测, 既保证了同步资源m_pInstace的安全, 同时又没又损失效率, 一举两得. |
|