C++中的单例模式及按需释放模型(五)

本文详细介绍了如何在C++中实现一个多线程安全的通用单例类实例获取器,通过使用临界区对象进行线程同步。文章探讨了单例类与获取器实例的关系,Windows下临界区的使用方法,以及如何在单例模型中正确使用临界区。最后,提供了一个测试程序例子,分析了多线程环境下单例模式的效率和行为。
摘要由CSDN通过智能技术生成

四、多线程安全的通用单例类实例获取器

例子工程的名称是SingletonThreadSafeInstanceGetter。

刚开始写本文时,本没有想实现多线程版本,主观上以为同通常的单例模式一样,多个多线程同步就可以了,很简单,让读者自己开发就好了,不过后来真正去思考时发现不是那么简单的,感觉对此还是很有介绍的必要。

1、单例类实例与单例类实例获取器实例的对应关系

在实现多线程安全的通用单例类实例获取器前,将用3小节分析一些问题,然后再给出具体的实现。

在前面《C++中的单例模式及按需释放模型(四)》已经给出了通用单例类实例获取器,我们来想想实际使用的时候的具体情况,对于一个单例类SingletonExample,使用这个模型在系统中只可能存在一个实例,但是其单例类实例获取器SingletonInstanceGetter有多少个实例呢,读者如果仔细阅读了前文,就会知道存在多个,也就是单例类实例同其实例获取器实例的关系是一对多,当所有的这个单例类实例获取器实例都释放了的时候,这个单例类实例也会被释放。

2、Windows中临界区的使用方法

要使用Windows中的临界区即CRITICAL_SECTION,一般都需要使用InitializeCriticalSection、EnterCriticalSection、LeaveCriticalSection、DeleteCriticalSection这4个API,具体函数含义这里不讲,如果不知道去查MSDN,这里只说一下4个API的调用位置,假设有主线程M,然后创建2个子线程T1、T2,3个线程工作时需要用到一个临界区C进行同步,那么调用函数的位置将是M中调用InitializeCriticalSection初始化C,然后创建T1、T2,在M、T1、T2中使用EnterCriticalSection/LeaveCriticalSection对C进行操作来同步,然后等T1、T2退出后M中调用DeleteCriticalSection来清理C,这个过程说明了什么,说明

A、InitializeCriticalSection/DeleteCriticalSection只在主线程中调用,工作中不会被调用,子线程不会调用这2个函数;

B、EnterCriticalSection/LeaveCriticalSection在工作中被调用,子线程只会调用到这2个函数。

3、如何在本单例模型中使用临界区

基于以上两点,我们分析在本单例模型中如何使用临界区

A、需要独立的临界区对象

要使用临界区,单例类实例获取器SingletonInstanceGetter的GetInstance方法中使用EnterCriticalSection/LeaveCriticalSection这个没有什么疑问,我们在单例类实例获取器SingletonInstanceGetter的构造和析构方法中使用InitializeCriticalSection/DeleteCriticalSection还是EnterCriticalSection/LeaveCriticalSection?这里应该还是使用EnterCriticalSection/LeaveCriticalSection,因为单例类实例获取器SingletonInstanceGetter的实例是在线程中创建和释放的,即它的构造析构函数是在线程中调用的,如果构造和析构方法中使用InitializeCriticalSection/DeleteCriticalSection,就会多次初始化和清理临界区,这是不可以的,那InitializeCriticalSection/DeleteCriticalSection在什么地方调用呢?应该在单例类实例获取器SingletonInstanceGetter的外部,即临界区不属于单例类实例获取器,不是组合关系,是独立于单例类实例获取器的,只是被其使用,所以我们需要为使用的临界区单独创建类管理。

B、需要一个临界区对象

那我们需要几个临界区对象呢?我们只需要一个,也就是对于一个单例类SingletonExample实例应该就对应一个临界区对象,即临界区对象也是一个单例类,同时对应多个单例类实例获取器SingletonInstanceGetter实例,这样既能保证多个单例类实例获取器SingletonInstanceGetter实例工作时可以使用这个临界区对象进行同步,同时不与其他单例类SingletonExampleTwo共用临界区,互相干扰,造成不必要的等待。

C、临界区对象的初始化和释放

我们既然建立了临界区对象,就可以在临界区对象的构造函数中调用InitializeCriticalSection,析构函数中调用DeleteCriticalSection,正如【四.2】中讲到的,这个临界区对象的创建应该在主线程中完成,然后在多线程中使用这个对象,等线程都退出后,在主线程中释放掉这个临界区对象。

4、临界区锁定类

A、临界区对象的实现

上面已经说明了临界区和某个单例类实例是一一对应关系,所以我们也使用模板类的方式建立临界区对象,模板参数就是单例类

临界区模板类的定义与实现

	template <typename T>
	class SingletonThreadLock
	{
		friend SingletonInstanceGetter<SingletonThreadLock<T>>::SingletonInstanceGetter
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值