线程安全的单实例模式模板化实现


单实例模式在对象创建和销毁时存在多线程安全问题,所以通常在这两个方法中加锁。为了有较高的效率,通常采用“双重检查加锁”机制。


#pragma once

template<class T, typename Synch = CLock>
class TSingleton
{
public:
	TSingleton(){};
	virtual ~TSingleton(){};

	static T* instance()
	{
		if(m_pInstance == NULL)
		{
			m_lock.Lock();
			if (m_pInstance == NULL)
			{
				m_pInstance = new T();
			}
			m_lock.Unlock();
		}

		return m_pInstance;
	}

	static void release()
	{
		if(m_pInstance != NULL)
		{
			m_lock.Lock();
			if (m_pInstance != NULL)
			{
				delete m_pInstance;
				m_pInstance = NULL;
			}
			m_lock.Unlock();
		}
	}
private:
	TSingleton(const TSingleton&);
	TSingleton& operator=(const TSingleton&);

private:
	volatile static T* m_pInstance;
	static Synch m_lock;
};

template<class T, typename Synch> T* TSingleton<T, Synch>::m_pInstance = NULL;
template<class T, typename Synch> Synch TSingleton<T, Synch>::m_lock;


使用:

class Test

{

friend class TSingleton<Test>;

......

};


如TSingleton<Test>即为一个单例模式的类实例。

可以

typedef TSingleton<Test> SingletonTest;

using SingletonTest = TSingleton<Test>;

创建类实例的别名,以方便使用。



问题:

double-checked singleton实现依然存在线程安全问题。

如 m_pInstance = new T();

这条代码包含了三个指令步骤:
1、分配内存;2、在内存位置上调用构造函数;3、将内存地址赋值给m_pInstance。
volatile关键字并不能组织CPU的乱序执行。
由于CPU的动态调度(乱序执行不相关的指令),步骤2和3顺序不相关,可能3早于2执行。即m_pInstance先得到地址,而此时对象还没有构造(完成)。<span style="font-family: Arial, Helvetica, sans-serif;">如果这时有另一线程调用Instance()函数,则会直接返回m_pInstance,而造成获取到不完整的对象。</span>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值