设计一个线程安全的单例(Singleton)模式

在设计单例模式的时候,虽然很容易设计出符合单例模式原则的类类型,但是考虑到垃圾回收机制以及线程安全性,需要我们思考的更多。有些设计虽然可以勉强满足项目要求,但是在进行多线程设计的时候。不考虑线程安全性,必然会给我们的程序设计带来隐患。此处,我们不介绍什么是单例模式,也不介绍如何设计简单的设计模式,因为你完全可以在书上或者在博客中找到。此处我们的目的就是设计一个使用的单例模式类。单例模式需要注意与思考的问题:

(1)如何仅能实例化一个对象?

(2)怎么样设计垃圾回收机制?

(3)如何确保线程安全性?

在思考了上述的几个问题后,首先设计一个线程安全的类,注意:由于CResGuard类会被多个线程访问,所以这个类除了构造函数与析构函数意外,其他成员都是线程安全的。

class CResGuard {
public:
	CResGuard()  { m_lGrdCnt = 0; InitializeCriticalSection(&m_cs); }
	~CResGuard() { DeleteCriticalSection(&m_cs); }

	// IsGuarded 用于调试
	BOOL IsGuarded() const { return(m_lGrdCnt > 0); }

public:
	class CGuard {
	public:
		CGuard(CResGuard& rg) : m_rg(rg) { m_rg.Guard(); };
		~CGuard() { m_rg.Unguard(); }

	private:
		CResGuard& m_rg;
	};

private:
	void Guard()   { EnterCriticalSection(&m_cs); m_lGrdCnt++; }
	void Unguard() { m_lGrdCnt--; LeaveCriticalSection(&m_cs); }

	// Guard/Unguard两个方法只能被内嵌类CGuard访问.
	friend class CResGuard::CGuard;

private:
	CRITICAL_SECTION m_cs;
	long m_lGrdCnt;
};

接下来我们需要设计一个符合上面三个条件的类。为了实现自动回收机制,我们使用了智能指针auto_ptr,尽管很多人不喜欢它,原因是使用不当,会产生不少陷阱,所以你完全可以用其他智能指针替代它。为了方便未来的使用,还使用了模版,如果你不喜欢,可以花两分钟的时间轻松的干掉它。

	namespace Pattern
	{
		template <class T>
		class Singleton
		{
		public:
			static inline T* instance();

		private:
			Singleton(void){}
			~Singleton(void){}
			Singleton(const Singleton&){}
			Singleton & operator= (const Singleton &){}

			static auto_ptr<T> _instance;
			static CResGuard _rs;
		};

		template <class T>
		auto_ptr<T> Singleton<T>::_instance;

		template <class T>
		CResGuard Singleton<T>::_rs;

		template <class T>
		inline T* Singleton<T>::instance()
		{
			if (0 == _instance.get())
			{
				CResGuard::CGuard gd(_rs);
				if (0 == _instance.get())
				{
					_instance.reset(new T);
				}
			}
			return _instance.get();
		}
//实现单例模式的类的地方,必须将宏定义放在声明文件中,
#define DECLARE_SINGLETON_CLASS( type ) 	friend class auto_ptr< type >; 	friend class Singleton< type >;
	}

单例我们虽然看似简单,但是有太多问题非常值得我们思考与深究,因为一定程度上,它深入到了C++语言机制,更可以加深你对此语言设计的理解程度。

时间: 2024-10-11 12:46:20

设计一个线程安全的单例(Singleton)模式的相关文章

如何写一个比较严谨的单例Singleton模式

iOS真正意义上的单例模式: 我们在程序中很多时候要保证一个类只有一个唯一的实例,一般情况下初始化对象是通过[[Class alloc]init]来完成的,alloc是分配内存空间,init是对象的初始化,分配对象内存空间的另一个方法是allocWithZone方法,实际操作中当调用alloc方法来给对象分配空间时,默认也调用了allocWithZone方法.如果我们在初始化对象的时候没有使用alloc方法,而是直接使用allocWithZone方法的话,就没法保证这个单例是真正意义上的单例了,

分享一个线程安全的单例模板类

单例模式应该说是最简单的设计模式了.在此分享一个线程安全的单例模板类. template <typename Type> class CSingleton { public: static Type* GetInstance() { // kBeingCreatedMarker用来表示单例实例正在创建过程中. // 此处初始化为1是因为操作系统不会分配地址为1的指针. static const volatile intptr_t kBeingCreatedMarker = 1; // 如果m_

C++实现一个线程安全的单例工厂

我们见到经常有人用 static 局部对象的方式实现了类似单例模式,最近发现一篇文章明确写明 编译器在处理  static局部变量的时候 并不是线程安全的 !!! http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx 于是实现了一个单例工厂  并且是线程安全的 #ifndef SINGLETONFACTORY_H #define SINGLETONFACTORY_H #include "windows.h"

Android与设计模式——单例(Singleton)模式

概念: java中单例模式是一种常见的设计模式.单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类仅仅能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. 3.单例类必须给全部其它对象提供这一实例. 单例模式确保某个类仅仅有一个实例.并且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机能够有若干个打印机,但仅仅能有一个Pri

写一个单例(Singleton),并说明单例的目的和好处

单例的目的:保证一个类只有单一的实例,也就是说你无法通过new来创建这个类的一个新实例. 单例的好处:当一个对象在程序内部只能有一个实例的时候,它可以保证我们不会重复创建,而是始终指向同一个对象. Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问. 第一种:在声明变量时实例化(也叫饿汉式单例模式),代码如下: public class Singleton { private s

单例 singleton

一.单例模式 特点:单例模式的类必须保证始终只有一个实例存在. 场景:在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次),应该让这个类创建出来的对象永远只有一个. 二.单例类的构建 1:为你的单例类声明一个静态的实例,并且初始化它的值为nil. 2:在获取实例的方法中,只有在静态实例为nil的时候,产生一个你的类的实例,这个实例通常被称为共享的实例. 3:重写allocWithZone 方法,用于确定:不能够使用其他的方法来创建我们不得实例,限制用户只能通过获取实例的方法得到这个类的

《连载 | 物联网框架ServerSuperIO教程》- 8.单例通讯模式开发及注意事项

1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架ServerSuperIO教程>2.服务实例的配置参数说明 <连载 | 物联网框架ServerSuperIO教程>- 3.设备驱动介绍 <连载 | 物联网框架ServerSuperIO教程>-4.如开发一套设备驱动,同时支持串口和网络通讯. <连载 | 物联网框架ServerSupe

设计模式之----单体(单例)模式

设计模式之--单体(单例)模式 1.介绍 从本章开始,我们会逐步介绍在JavaScript里使用的各种设计模式实现,在这里我不会过多地介绍模式本身的理论,而只会关注实现.OK,正式开始. 在传统开发工程师眼里,单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象.在JavaScript里,单例作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象. 2. 简单单体与闭包单体 在JavaS

python实现单例工厂模式

class CarFactory: '''python实现单例工厂模式''' __obj = None __flg_init = True def __new__(cls, *args, **kwargs): if cls.__obj is None: cls.__obj = object.__new__(CarFactory) return cls.__obj def __init__(self): if CarFactory.__flg_init: print('工厂产生了') CarFac