再谈Singleton

再谈Singleton

前些时候写了一篇关于Singleton模式的使用心得,发布在这个页面:

http://blog.csdn.net/Li_Shugan1/archive/2010/08/09/5797873.aspx

后来在实际应用的过程中又出现了一些问题,其间查了一些资料,主要是Modern C++ Design,解决了Singleton在C++中会出现的问题,其方案多有借鉴Modern C++ Design中的内容,但是对析构顺序的控制,是自己的想法,自我感觉要优于这本书的的,呵呵总的来说会到的问题主要三个:

  1. Singleton用那种方式创建。用类的静态指针,还是函数内的静态变量,或者直接用类的静态对象。
  2. 多个Singleton析构的顺序问题。
  3. 对多线程的支持。

现在就一个一个慢慢道来。

Singleton的创建

3种创建方式的优缺点如下图所示.

 

这上面提到的Resource Leak是指诸如Network之类的资源没有释放。一开始我还以为会为内存泄漏,后来才知道静态指针是不会出现内存泄漏的,因为程序在退出时,操作系统负责清理所有的内存空间。
   另外,这里提到的strong bugs,对 Implementation2来说可以来自两方面,Singleton的创建顺序和析构顺序。Implementation3主要是析构的顺序。

Singleton析构的顺序

 这里只对Implementation3给个反例:

// Singleton.cpp : Defines the entry point for the console application.
//

#include <string>
#include <iostream>
using namespace std;
class Log
{
public:
	static Log* GetInstance()
	{
		static Log oLog;
		return &oLog;
	}

	void Output(string strLog)
	{
		cout<<strLog<<(*m_pInt)<<endl;
	}
private:
	Log():m_pInt(new int(3))
	{
	}
	~Log()
	{cout<<"~Log"<<endl;
		delete m_pInt;
		m_pInt = NULL;
	}
	int* m_pInt;
};

class Context
{
public:
	static Context* GetInstance()
	{
		static Context oContext;
		return &oContext;
	}
	~Context()
	{
		Log::GetInstance()->Output(__FUNCTION__);
	}

	void fun()
	{
		Log::GetInstance()->Output(__FUNCTION__);
	}
private:
	Context(){}
	Context(const Context& context);
};

int main(int argc, char* argv[])
{
	Context::GetInstance()->fun();
	return 0;
}


 

 在这个反例中有两个Singleton: Log和Context,Context的fun和析构函数会调用Log来输出一些信息,结果程序Crash掉了,该程序的运行的序列图如下(其中画红框的部分是出问题的部分):

 

对多线程的支持

 对多线程的支持大学可以参与《Modern C++ Design》中的方案,这里主要解决析构的顺序问题。

解决方案

  1. 由于Implementation1是没有创建的顺序问题的(当然如果你的两个Singleton创建时互相依赖,这连神仙都没办法,呵呵),我们可以继续延用这种方式。
  2. 对于析构的顺序,我们可以用一个容器来管理它,对于前面的例子中的两个Singleton: Log和Context,选释放Context,再释放Log,如果出现了循环依赖关系,我们要给出异常,并输出循环依赖环。

       我的思路是这样的,(1)用一个特别的单例SingletonMgr来管理所有的单例,每个单例都必须register到SingletonMgr中,对会在析构函数中依赖别的Singleton的来说,它还要做一点事,那就是申明这种依赖,对上面这个反例,在实现Context的GetInstance方法时,要申明一下它会在在析构时依赖Log;

            (2)在SingletonMgr析构时,按依赖关系对所有的Singleton的析构顺序排序,然后来调用各个Singleton的析构方法。

 

        SingletonMgr的结构图如下:

 

          每一个单例,在SingletonMgr中都有一SingletonItem与其对应,SingletonItem中存储该单例的名字,Destory方法和它所依赖的其他单例。

          最为复杂的就是最后的排序算法啦,这里采用的 Depth First Traverse算法对其排序的,在排序的过程中会检测是否出现了依赖环,如果出现了依赖环,在打印了该依赖环后抛出异常。

算法框架如下图所示:

 

                             

 其中的Depth First Traverse步骤如图:

  ······················

 

  在使用Depth First Traverse进行排序时,涉及到了一个SingletonItem的状态问题。SingletonItem一共有5种状态:

   (1)  E_UnSort: 在开始Sort之前,所有的SingletonItem都处于这个状态。

   (2)  E_Sorting:在处理一个SingletonItem的依赖时,会处于这个状态。

   (3)  E_Sorted:如果一个Item已经完全Sort好了,就会到这个状态。
   (4)  E_CannotSort:在处理完一个Item的依赖时,会被置为这个状态。
   (5)  E_SelfSorted:出现了依赖环。、

     SingletonMgr的定义如下:

 

#ifndef SINGLETONMGR_HPP
#define SINGLETONMGR_HPP
#include <vector>
#include <stack>
#include <string>
#include <list>
using std::vector;
using std::stack;
using std::string;
using std::list;
typedef void (*SingletonReleaseFun)(void);
class SingletonItem
{
public:
	enum ESortState
	{
		E_UnSort,
		E_Sorting,
		E_Sorted,
		E_CannotSort,
		E_SelfSorted
	};
	SingletonItem(const string& strName,SingletonReleaseFun releaseFun);
	~SingletonItem();
	const string& Name()const{return m_strName;}
	void	SetState(ESortState eState){m_eSortState = eState;}
	ESortState GetState(void){return m_eSortState;}

	void	Push(SingletonItem* pDependencyItem);
	SingletonItem* Pop(void);
	bool	IsEmpty(void){return m_stackDependencys.empty();}

	void SetReleaseFun(SingletonReleaseFun releaseFun){m_funRelease = releaseFun;}
	void Release();
private:
	SingletonItem(const SingletonItem&);
	string				m_strName;
	SingletonReleaseFun	m_funRelease;
	ESortState			m_eSortState;
	stack<SingletonItem*>	m_stackDependencys;
};
class SingletonMgr
{
public:
	static SingletonMgr*	GetInstance();
	void Regesiter(const string& strName,SingletonReleaseFun pReleaseFun);
	void AddDependency(const string& strSingleton1,const string& strSingleton2);
private:
	static void Release(void);
	void	SortItems(void);
	void	DepthFirstTraverse(SingletonItem *pItem,vector<SingletonItem*>& sortingItems);
	void	OutputLoop(SingletonItem *pItem,vector<SingletonItem*>& sortingItems);
	void	AdjustPosition(SingletonItem *pItem,vector<SingletonItem*>& sortingItems);
	size_t  FindPosIn(vector<SingletonItem*>& items,SingletonItem* pItem);
	SingletonItem* GetSingleton(const string& pItem);
	SingletonMgr();
	SingletonMgr(const SingletonMgr&);
	~SingletonMgr(void);
	vector<SingletonItem*>	m_vSingletons;
	list<SingletonItem*>	m_listSortedSingletons;
};																													
#endif

 其实现如下:

#include "SingletonMgr.h"
#include <iostream>
#include <cassert>
#include <algorithm>
using std::cout;
using std::endl;
SingletonItem::SingletonItem(const string& strName,SingletonReleaseFun releaseFun):
m_strName(strName)
,m_funRelease(releaseFun)
,m_eSortState(E_UnSort)
{
}
SingletonItem::~SingletonItem()
{

}

void	SingletonItem::Release()
{
	if(NULL != m_funRelease)
	{
		m_funRelease();
	}
}
void	SingletonItem::Push(SingletonItem* pItem)
{
	m_stackDependencys.push(pItem);
}

SingletonItem* SingletonItem::Pop(void)
{
	SingletonItem* pItem = m_stackDependencys.top();
	m_stackDependencys.pop();
	return pItem;
}

SingletonMgr*	SingletonMgr::GetInstance()
{
	static SingletonMgr oSingletonMgr;
	return &oSingletonMgr;
}
SingletonMgr::SingletonMgr(void)
{
}

SingletonMgr::~SingletonMgr(void)
{
	SortItems();
	for(list<SingletonItem*>::iterator it = m_listSortedSingletons.begin();
		it != m_listSortedSingletons.end();
		++it)
	{
		(*it)->Release();
	}

	for(list<SingletonItem*>::iterator it = m_listSortedSingletons.begin();
		it != m_listSortedSingletons.end();
		++it)
	{
		delete *it;
	}
}

void	SingletonMgr::SortItems(void)
{
	vector<SingletonItem*> sortingItems;
	for(size_t nIndex = 0; nIndex < m_vSingletons.size(); ++nIndex )
	{
		SingletonItem* pItem = m_vSingletons[nIndex];
		if(NULL != pItem && SingletonItem::E_Sorted != pItem->GetState())
		{
			DepthFirstTraverse(pItem,sortingItems);
		}

		if(sortingItems.size() > 0)
		{
			m_listSortedSingletons.insert(m_listSortedSingletons.begin(),
				sortingItems.begin(),sortingItems.end());
			for (size_t nPos = 0;nPos < sortingItems.size();++nPos)
			{
				SingletonItem* pItem = sortingItems[nPos];
				if(NULL != pItem)
				{
					pItem->SetState(SingletonItem::E_Sorted);
				}
			}
			sortingItems.clear();
		}
	}
}

void SingletonMgr::DepthFirstTraverse(SingletonItem *pItem,vector<SingletonItem*>& sortingItems)
{
	switch(pItem->GetState())
	{
	case SingletonItem::E_Sorted:
		break;
	case SingletonItem::E_Sorting: //encounter a loop.
		//output the loop
		OutputLoop(pItem,sortingItems);
		pItem->SetState(SingletonItem::E_CannotSort);
    	assert(0);	
		break;
	case SingletonItem::E_CannotSort://encounter another loop.
		//output the loop
		OutputLoop(pItem,sortingItems);
		assert(0);	
		break;		
	case SingletonItem::E_SelfSorted://need adjust
		AdjustPosition(pItem,sortingItems);
		break;
	default:
		{
			pItem->SetState(SingletonItem::E_Sorting);
			sortingItems.push_back(pItem);
			while(!pItem->IsEmpty())
			{
				DepthFirstTraverse(pItem->Pop(),sortingItems);
			}
			pItem->SetState(SingletonItem::E_SelfSorted);
		}
		break;
	}
}

void	SingletonMgr::OutputLoop(SingletonItem *pItem,vector<SingletonItem*>& sortingItems)
{
	cout<<pItem->Name();
	for(vector<SingletonItem*>::reverse_iterator it = sortingItems.rbegin();
		(*it)->Name() != pItem->Name();++it)
	{
		cout<<"<--"<<(*it)->Name();
	}
	cout<<"<--"<<pItem->Name()<<endl;
}

void	SingletonMgr::AdjustPosition(SingletonItem *pItem,vector<SingletonItem*>& sortingItems)
{
	size_t nItemPos = FindPosIn(sortingItems,pItem);
	vector<SingletonItem*>::iterator it4Item = find(sortingItems.begin(),sortingItems.end(),pItem);
	for (size_t nPos = nItemPos + 1;
		nPos < sortingItems.size();++nPos)
	{
		SingletonItem* pAdjustItem = sortingItems.at(nPos);
		if (NULL != pAdjustItem && SingletonItem::E_Sorting == pAdjustItem->GetState())
		{
			sortingItems.erase(find(sortingItems.begin(),sortingItems.end(),pAdjustItem));
			it4Item = sortingItems.insert(it4Item,pAdjustItem);
			++it4Item;
		}
	}
}

size_t  SingletonMgr::FindPosIn(vector<SingletonItem*>& items,SingletonItem* pItem)
{
	for(size_t nPos = 0;nPos < items.size();++nPos)
	{
		if (pItem == items[nPos])
		{
			return nPos;
		}
	}
	return -1;
}
void SingletonMgr::Regesiter(const string& strName,SingletonReleaseFun pReleaseFun)
{
	SingletonItem* pItem = GetSingleton(strName);
	pItem->SetReleaseFun(pReleaseFun);
}

void SingletonMgr::AddDependency(const string& strSingleton1,const string& strSingleton2)
{
	SingletonItem* pItem = GetSingleton(strSingleton1);
	pItem->Push(GetSingleton(strSingleton2));
}

SingletonItem* SingletonMgr::GetSingleton(const string& strSingleton)
{
	for(vector<SingletonItem*>::iterator it = m_vSingletons.begin();
		it != m_vSingletons.end();
		++it)
	{
		if((*it)->Name() == strSingleton)
		{
			return *it;
		}
	}
	m_vSingletons.push_back(new SingletonItem(strSingleton,NULL));
	return m_vSingletons.back();
}

 为了方便实现一个Singleton,还定义了如下宏:

 

#ifndef _SINGLETONDEF_H
#define _SINGLETONDEF_H
#include "SingletonMgr.h"

#define DECLARE_SINGLETON(Singleton)																															\
	public:																																						\
		static Singleton* GetInstance(void);																													\
	private:																																					\
		Singleton(const Singleton&) ;																															\
		Singleton& operator=(const Singleton&) ;																												\
		static void Release() ;																																	\
		static Singleton*	g_pInstance;
		
#define BEGIN_IMPLEMENT_SINGLETON(Singleton)																													\
	Singleton *Singleton::g_pInstance = NULL;																													\
	Singleton* Singleton::GetInstance()																															\
	{																																							\
		SingletonMgr::GetInstance()->Regesiter(#Singleton,Singleton::Release);																					\
		Singleton::g_pInstance = new																														
#define END_IMPLEMENT_SINGLETON(Singleton)																														\
		return Singleton::g_pInstance;																															\
	}																																							\
	void Singleton::Release()																																	\
	{																																							\
		delete Singleton::g_pInstance;																															\
		Singleton::g_pInstance = NULL;																															\
	}

#define DECLARE_DEPENDENCY(Singleton1,Singleton2)																												\
	SingletonMgr::GetInstance()->AddDependency(#Singleton1,#Singleton2);
#endif


 


 

  有了这些,再实现上面的Context和Log如下:

 

// Singleton.cpp : Defines the entry point for the console application.
//

#include <string>
#include <iostream>
using namespace std;
#include "SingletonDef.h"
class Log
{
	DECLARE_SINGLETON(Log);
	Log():m_pInt(new int(3))
	{
	}
public:
	void Output(string strLog)
	{
		cout<<strLog<<(*m_pInt)<<endl;
	}

	~Log()
	{cout<<"~Log"<<endl;
		delete m_pInt;
		m_pInt = NULL;
	}
	int* m_pInt;
};

BEGIN_IMPLEMENT_SINGLETON(Log)
	Log();
END_IMPLEMENT_SINGLETON(Log)
class Context
{
	DECLARE_SINGLETON(Context)
	Context(){}
public:
	~Context()
	{
		Log::GetInstance()->Output(__FUNCTION__);
	}

	void fun()
	{
		Log::GetInstance()->Output(__FUNCTION__);
	}
};
BEGIN_IMPLEMENT_SINGLETON(Context)
	Context();
	DECLARE_DEPENDENCY(Context,Log);
END_IMPLEMENT_SINGLETON(Context)
int main(int argc, char* argv[])
{
	Context::GetInstance()->fun();
	return 0;
}


 再运行程序就不会Crash了,当然,希望大家能用一些更为复杂的例子来检测一下我这个算法^_^

posted @ 2010-10-02 19:51  李书淦  阅读(1399)  评论(0编辑  收藏  举报