//========================================================================
//TITLE:
// 如何写优雅的代码(5)--远离临界区噩梦
//AUTHOR:
// norains
//DATE:
// Tuesday 01- December-2009
//Environment:
// WINDOWS CE 5.0
//========================================================================
在平时的多线程编程中,我们往往离不开临界区。会用,甚至是用得好的朋友,估计不少;但用得万无一失的,相对而言,可能就会少很多。
不信?我们来看看下面这段代码:
view plain copy to clipboard print ?
- try
- {
- EnterCriticalSection(&g_cs);
- Cal3rdPartCode(pParam);
- LeaveCriticalSection(&g_cs);
- }
- catch(...)
- {
-
-
- }
try { EnterCriticalSection(&g_cs); Cal3rdPartCode(pParam); LeaveCriticalSection(&g_cs); } catch(...) { //There is error //dwRet = 0; }
这段代码看起来似乎没有什么问题?但如果说,这段代码会引发孤立临界区的问题,你会信么?换句话说,如果Cal3rdPartCode(pParam)函数会抛出异常,那么代码就直接跳转到catch部分。那事情就严重了,因为代码根本就没有调用LeaveCriticalSection(&g_cs),将g_cs这临界区完全孤立了起来,别的线程就只能一直等待该临界区。
似乎情况很糟糕,不是么?当然,糟糕并不代表陷入世界末日,虽然路途上充满了荆棘,但毕竟我们还是能看到阳光。
我们总不能在一棵树上吊死吧。换个角度,临界区的使用,必须是EnterCriticalSection和LeaveCriticalSection配套使用。那么我们想想,C++里面,有什么东西是强制配套的,根本不用使用者干预的?也许有的朋友已经想到了。没错,是类,类的构造函数和析构函数。
正常使用的话,无论使用者愿不愿意,类的构造函数和析构函数都是被编译器强制配套使用。所以,我们可以在构造函数中调用EnterCriticalSection,在析构函数则是LeaveCriticalSection。
根据此思想,我们最简单的用类来调用临界区的代码诞生了:
view plain copy to clipboard print ?
- class CLock
- {
- public:
- CLock(LPCRITICAL_SECTION pCriticalSection):
- m_ pCriticalSection(pCriticalSection)
- {
- EnterCriticalSection(m_ pCriticalSection);
- };
-
- virtual ~CLock()
- {
- LeaveCriticalSection (m_ pCriticalSection);
- };
-
- private:
- LPCRITICAL_SECTION m_ pCriticalSection;
- };
-
class CLock { public: CLock(LPCRITICAL_SECTION pCriticalSection): m_ pCriticalSection(pCriticalSection) { EnterCriticalSection(m_ pCriticalSection); }; virtual ~CLock() { LeaveCriticalSection (m_ pCriticalSection); }; private: LPCRITICAL_SECTION m_ pCriticalSection; };
使用上也是简单明了:
view plain copy to clipboard print ?
- void CallFunctionProc()
- {
- CLock lock(&g_cs);
- }
-
void CallFunctionProc() { CLock lock(&g_cs); }
但这样完美了么?很遗憾,这只是万里长征的第一步,我们的路还很漫长。最根本的问题,我们如何确保传入的临界区指针是有效的?换句话说,我们无法保证传入的临界区指针是没有调用过DeleteCriticalSection的。
如果代码是如下的书写,很明显,肯定会有我们无法预料的异常:
view plain copy to clipboard print ?
- void CallFunctionProc()
- {
- DeleteCriticalSection(&g_cs);
- ...
-
- CLock lock(&g_cs);
- }
-
void CallFunctionProc() { DeleteCriticalSection(&g_cs); ... CLock lock(&g_cs); }
那有没有这么一种机制,我们可以通过它进入临界区,但我们却不能让它删除临界区,或是即使删除了,我们也有足够的信息获知。
万事无绝对,既然我们能想到,那么我们就能做到。人有多大胆,地有多大产,在这个奇迹倍出的IT界,有时候也并不只是一句华而不实的口号。
首先,我们将创建临界区的操作封装于类中,使用者只能获得创建的序号;然后,如果想进入临界区,只要传入序号即可;最后,如果不需要该临界区,那么传入序号删除即可。这样的好处是,通过序号这个桥梁,既能使用临界区的功能,又不会引发临界区的不稳定。
我们先来看看创建的函数:
view plain copy to clipboard print ?
- static DWORD CLock::Create()
- {
- CRITICAL_SECTION* pcsCriticalSection = new CRITICAL_SECTION();
- if(pcsCriticalSection == NULL)
- {
- return Lock::INVALID_INDEX;
- }
-
- __try
- {
- InitializeCriticalSection(pcsCriticalSection);
- }
- __except(GetExceptionCode() == STATUS_NO_MEMORY)
- {
-
-
- delete pcsCriticalSection;
-
- return Lock::INVALID_INDEX;
- }
-
- return AddTable(pcsCriticalSection);
- }
-
static DWORD CLock::Create() { CRITICAL_SECTION* pcsCriticalSection = new CRITICAL_SECTION(); if(pcsCriticalSection == NULL) { return Lock::INVALID_INDEX; } __try { InitializeCriticalSection(pcsCriticalSection); } __except(GetExceptionCode() == STATUS_NO_MEMORY) { //Failed to intialize the critical section, so delete the object created by new operate. delete pcsCriticalSection; return Lock::INVALID_INDEX; } return AddTable(pcsCriticalSection); }
虽然我们将Create函数封装于CLock类中,但我们不打算需要通过对象才能调用,所以我们以static进行修饰,让其成为类函数。那么,我们调用的时候,就可以直接通过类作用域使用:
view plain copy to clipboard print ?
- DWORD dwIndex = CLock::Create();
DWORD dwIndex = CLock::Create();
我们留意一下这句:
view plain copy to clipboard print ?
- CRITICAL_SECTION* pcsCriticalSection = new CRITICAL_SECTION();
CRITICAL_SECTION* pcsCriticalSection = new CRITICAL_SECTION();
这句代码用来在栈中创建CRITICAL_SECTION对象。之所以这么做,是因为如果使用局部变量,那么在函数返回时,局部变量就被删除。而通过new创建出来的对象,除非我们调用delete,否则在程序运行期中一直存在。这样就能达到创建的目的。
接下来的异常捕获部分可能是大家都会忽略的。根据MSDN的文档,InitializeCriticalSection并不保证绝对能创建成功。当内存不足时,就会抛出STATUS_NO_MEMORY异常。所以我们必须捕获这个异常,并进行相应的处理。
话又说回来,在我们平时直接调用临界区的方式中,如果出现这个异常是很麻烦的事情。因为CRITICAL_SECTION对象的内部细节没有公布,我们无法根据CRITICAL_SECTION对象来确定临界区是否有效,也就无法保证代码的健壮性。
如果一切顺利,我们就通过AddTable将临界区放入存储空间中。
AddTable的实现如下:
view plain copy to clipboard print ?
- static DWORD CLock::AddTable(CRITICAL_SECTION* pcsCriticalSection)
- {
- if(ms_pmpCriticalSection == NULL)
- {
- ms_pmpCriticalSection = new std::map<DWORD,CriticalSectionData>();
-
- if(ms_pmpCriticalSection == NULL)
- {
- return Lock::INVALID_INDEX;
- }
- else
- {
- ms_dwIndex = 0;
- }
- }
-
- CriticalSectionData newCriticalSectionData = {pcsCriticalSection,0};
- InterlockedIncrement(reinterpret_cast<LONG *>(&ms_dwIndex));
- ms_pmpCriticalSection->insert(std::make_pair(ms_dwIndex,newCriticalSectionData));
-
- return ms_dwIndex;
- }
-
static DWORD CLock::AddTable(CRITICAL_SECTION* pcsCriticalSection) { if(ms_pmpCriticalSection == NULL) { ms_pmpCriticalSection = new std::map<DWORD,CriticalSectionData>(); if(ms_pmpCriticalSection == NULL) { return Lock::INVALID_INDEX; } else { ms_dwIndex = 0; } } CriticalSectionData newCriticalSectionData = {pcsCriticalSection,0}; InterlockedIncrement(reinterpret_cast<LONG *>(&ms_dwIndex)); ms_pmpCriticalSection->insert(std::make_pair(ms_dwIndex,newCriticalSectionData)); return ms_dwIndex; }
ms_pmpCriticalSection是一个成员变量指针,其在头文件声明如下:
view plain copy to clipboard print ?
- static std::map<DWORD,CriticalSectionData> *ms_pmpCriticalSection;
static std::map<DWORD,CriticalSectionData> *ms_pmpCriticalSection;
CriticalSectionData是我们定义的一个结构体,有两个成员变量,一个是指向临界区对象,另一个则记录了进入该临界区的次数:
view plain copy to clipboard print ?
- struct CriticalSectionData
- {
- CRITICAL_SECTION *pCriticalSection;
- LONG lLockCount;
- };
struct CriticalSectionData { CRITICAL_SECTION *pCriticalSection; LONG lLockCount; };
看到这里,可能有的朋友说,CRITICAL_SECTION不是有个LockCount成员么,直接使用它不就行了?从理论上来说,这是可以的。但对于该结构,微软并没有描述文档,换而言之,微软保留了变更其成员的权利。虽然我们可以相信,微软一般不会做这种费力不讨好的事,但谁知道哪天微软又心血来潮呢?所以,与其将代码建立于微软的信任,还不如建立于我们的掌握之中。
我们稍微回头看看,为什么我们定义ms_pmpCriticalSection为指针,而不是直接作为普通变量?也就是说,为什么不直接这样定义:
view plain copy to clipboard print ?
- static std::map<DWORD,CriticalSectionData> ms_mpCriticalSection;
static std::map<DWORD,CriticalSectionData> ms_mpCriticalSection;
如果这样定义,会有很大的风险。因为如果有一个类在构造函数调用了CLock::Create,而该类之后的对象又有一个静态声明,那么就会涉及到静态变量初始化顺序的不可控问题。因为在你调用CLock::Create的时候,ms_mpCriticalSection对象很有可能还有进行初始化。
例如:
view plain copy to clipboard print ?
- class CTest
- {
- public:
- CText():
- m_dwLock(CLock::Create())
- {
- }
-
- private:
- DWORD m_dwLock;
- };
class CTest { public: CText(): m_dwLock(CLock::Create()) { } private: DWORD m_dwLock; };
view plain copy to clipboard print ?
-
- static CTest test;
//这里很可能会出错,因为其构造函数调用了CLock::Create,而ms_mpCriticalSection很可能还没有进行初始化 static CTest test;
为了避免静态变量初始化导致的问题,我们只能采用new来进行分配。
在这里还有一个小技巧,为了避免繁琐的算法,我们直接采用了STL的map。这样,在后续的查找中,我们就能比较轻松。
既然返回的只是序号,那么我们的构造函数也必然需要进行相应的修改:
view plain copy to clipboard print ?
- CLock::CLock(DWORD dwIndex,BOOL *pRes = NULL):
- m_pcsCriticalSection(NULL)
- {
-
- if(pRes != NULL)
- {
- *pRes = FALSE;
- }
-
- m_pcsCriticalSection = GetObject(dwIndex);
- if(m_pcsCriticalSection != NULL)
- {
- if(pRes != NULL)
- {
- *pRes = TRUE;
- }
-
- InterlockedIncrement(&m_pcsCriticalSection->lLockCount);
- EnterCriticalSection(m_pcsCriticalSection->pCriticalSection);
- }
- }
-
CLock::CLock(DWORD dwIndex,BOOL *pRes = NULL): m_pcsCriticalSection(NULL) { //In order to make the source code simple, set the result as FALSE at first. if(pRes != NULL) { *pRes = FALSE; } m_pcsCriticalSection = GetObject(dwIndex); if(m_pcsCriticalSection != NULL) { if(pRes != NULL) { *pRes = TRUE; } InterlockedIncrement(&m_pcsCriticalSection->lLockCount); EnterCriticalSection(m_pcsCriticalSection->pCriticalSection); } }
从使用角度来说,我们只需要一个序号的形参即可。但我们想知道能不能成功进入临界区,而构造函数又不能拥有返回值,所以我们就额外多增加了一个pRes形参,用来在函数返回后指明当前进入临界区的状况。
GetObject是我们定义的一个函数,具体实现将在后面说明。现在只需要知道其实返回创建的一个临界区数据。如果获取一个临界区数据对象不为NULL,那么我们在进入临界区之前,先将lLockCount的计数增加1,标明当前进入临界区的次数。
其实很简单,和之前我们的最简单的构造函数相比,只是传入的形参不同。而恰恰只是这一点不同,就能使我们的代码临界区有一个质的飞跃。
再转回头,我们看看GetObject的实现:
view plain copy to clipboard print ?
- CLock::CriticalSectionData* CLock::GetObject(DWORD dwIndex)
- {
- if(ms_pmpCriticalSection == NULL)
- {
- ASSERT(FALSE);
- return NULL;
- }
-
- std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->find(dwIndex);
- if(iter != ms_pmpCriticalSection->end())
- {
- return &iter->second;
- }
- else
- {
- return NULL;
- }
-
- }
CLock::CriticalSectionData* CLock::GetObject(DWORD dwIndex) { if(ms_pmpCriticalSection == NULL) { ASSERT(FALSE); return NULL; } std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->find(dwIndex); if(iter != ms_pmpCriticalSection->end()) { return &iter->second; } else { return NULL; } }
代码并不复杂,只是从ms_pmpCriticalSection搜索出对应序号的数值,然后返回。如果该序号不存在,则返回NULL。
到这里,使用上的功能我们基本上已经完成。但似乎还缺了点什么,对,没错,还缺删除函数。删除函数并不复杂,删除临界区后,然后调用delete删除创建的栈,最后再从ms_pmpCriticalSection中删掉相应的序号即可。但我们需要考虑到使用者的便利性,不仅可以删除对应序号的对象,还能简单地删除所有。所以,对于删除函数,我们定义两个。而这两个删除函数,都应该通过不同的手法调用这个内部删除函数:
view plain copy to clipboard print ?
- static BOOL CLock::Delete(const std::map<DWORD,CriticalSectionData>::iterator &iter)
- {
- if(ms_pmpCriticalSection == NULL)
- {
- ASSERT(FALSE);
- return FALSE;
- }
-
- if(iter == ms_pmpCriticalSection->end())
- {
- return FALSE;
- }
-
- if(GetLockCount(iter->first) != 0)
- {
- ASSERT(FALSE);
- return FALSE;
- }
-
- if(iter->second.pCriticalSection == NULL)
- {
- return FALSE;
- }
-
- DeleteCriticalSection(iter->second.pCriticalSection);
- delete iter->second.pCriticalSection;
-
- return TRUE;
- }
-
static BOOL CLock::Delete(const std::map<DWORD,CriticalSectionData>::iterator &iter) { if(ms_pmpCriticalSection == NULL) { ASSERT(FALSE); return FALSE; } if(iter == ms_pmpCriticalSection->end()) { return FALSE; } if(GetLockCount(iter->first) != 0) { ASSERT(FALSE); return FALSE; } if(iter->second.pCriticalSection == NULL) { return FALSE; } DeleteCriticalSection(iter->second.pCriticalSection); delete iter->second.pCriticalSection; return TRUE; }
形参是传入一个迭代器,然后根据该迭代器做相应的操作。
那么,我们public的删除相应序号的函数可以如下:
view plain copy to clipboard print ?
- BOOL CLock::Delete(DWORD dwIndex)
- {
- if(ms_pmpCriticalSection == NULL)
- {
- ASSERT(FALSE);
- return FALSE;
- }
-
- std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->find(dwIndex);
- if(Delete(iter) != FALSE)
- {
- ms_pmpCriticalSection->erase(iter);
-
- CheckAndDeleteCriticalSection();
-
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-
- }
-
BOOL CLock::Delete(DWORD dwIndex) { if(ms_pmpCriticalSection == NULL) { ASSERT(FALSE); return FALSE; } std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->find(dwIndex); if(Delete(iter) != FALSE) { ms_pmpCriticalSection->erase(iter); CheckAndDeleteCriticalSection(); return TRUE; } else { return FALSE; } }
函数过程简单明了,从通过find函数查找相应key的位置,然后传递给Delete函数。如果Delete返回值为TRUE,那么我们就通过erase擦除。我们之所以没有在Delete(const std::map<DWORD,CriticalSectionData>::iterator &iter)函数中进行擦除,是因为map的迭代器,只要一删除,就会失效,这对后续的操作有所不利。所以,我们只能根据其返回值再确定是否删除。
CheckAndDeleteCriticalSection()函数用来判断ms_pmpCriticalSection是否为空,如果为空,直接调用delete删除该指针:
view plain copy to clipboard print ?
- static void CLock::CheckAndDeleteCriticalSection()
- {
- if(ms_pmpCriticalSection->empty() != FALSE)
- {
- delete ms_pmpCriticalSection;
- ms_pmpCriticalSection = NULL;
- }
- }
static void CLock::CheckAndDeleteCriticalSection() { if(ms_pmpCriticalSection->empty() != FALSE) { delete ms_pmpCriticalSection; ms_pmpCriticalSection = NULL; } }
有了这些基础,那么我们的删除所有的函数就简单了:
view plain copy to clipboard print ?
- static void CLock::DeleteAll()
- {
- if(ms_pmpCriticalSection == NULL)
- {
- ASSERT(FALSE);
- return;
- }
-
- for(std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->begin(); iter != ms_pmpCriticalSection->end(); )
- {
-
- if(Delete(iter) != FALSE)
- {
- ms_pmpCriticalSection->erase(iter ++);
- }
- else
- {
- ++ iter;
- }
- }
-
- CheckAndDeleteCriticalSection();
-
- }
-
static void CLock::DeleteAll() { if(ms_pmpCriticalSection == NULL) { ASSERT(FALSE); return; } for(std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->begin(); iter != ms_pmpCriticalSection->end(); ) { //The iterator would be destroy when you call erase,so I must call just as follows. if(Delete(iter) != FALSE) { ms_pmpCriticalSection->erase(iter ++); } else { ++ iter; } } CheckAndDeleteCriticalSection(); }
首先我们判断ms_pmpCriticalSection是否为NULL,为NULL则什么都不做,返回。然后,再遍历整个存储空间,传入其相应的迭代器进行操作。如果Delete返回不为FALSE,我们就调用erase进行删除。
在这里一个小细节需要留意,就是这段代码:
view plain copy to clipboard print ?
- for(std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->begin(); iter != ms_pmpCriticalSection->end(); )
- {
-
- if(Delete(iter) != FALSE)
- {
- ms_pmpCriticalSection->erase(iter ++);
- }
- else
- {
- ++ iter;
- }
- }
-
for(std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->begin(); iter != ms_pmpCriticalSection->end(); ) { //The iterator would be destroy when you call erase,so I must call just as follows. if(Delete(iter) != FALSE) { ms_pmpCriticalSection->erase(iter ++); } else { ++ iter; } }
对于这段代码,我们不能这么改写:
view plain copy to clipboard print ?
- for(std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->begin(); iter != ms_pmpCriticalSection->end();++ iter )
- {
-
- if(Delete(iter) != FALSE)
- {
- ms_pmpCriticalSection->erase(iter);
- }
-
- }
for(std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->begin(); iter != ms_pmpCriticalSection->end();++ iter ) { //The iterator would be destroy when you call erase,so I must call just as follows. if(Delete(iter) != FALSE) { ms_pmpCriticalSection->erase(iter); } }
因为我们知道,map容器只要进行erase操作,那么相应的迭代器就会失效。如果采用的是后面一种写法,那么我们调用erase操作后,iter就已经无效,循环中的iter就变成一个不可预料的操作。
现在,就是完整罗列代码的时候了:
头文件:
#pragma once #include "Windows.h" #include <map> namespace Lock { const DWORD INVALID_INDEX = 0xFFFFFFFF; }; class CLock { public: //---------------------------------------------------------------------------------------- //Description: // Create the lock object and return the index //Return Values: // If the value is INVALID_INDEX, it means failed. Others is succeeded. //----------------------------------------------------------------------------------------- static DWORD Create(); //--------------------------------------------------------------------------------------------- //Description: // Delete all the created critical section.When you call the function,you must be sure that //there isn't other threads to enter the critical section.After succeed in calling the function, //the GetSize() returns 0, otherwise it doesn't delete all the critical section object. //--------------------------------------------------------------------------------------------- static void DeleteAll(); //--------------------------------------------------------------------------------------------- //Description: // Delete the created critical section on the index. //Parameters: // dwIndex : [in]The index of object to delete //Return Values: // FALSE means failed, maybe the index is locked. //--------------------------------------------------------------------------------------------- static BOOL Delete(DWORD dwIndex); //---------------------------------------------------------------------------------------- //Description: // Get the size of the the critical section //---------------------------------------------------------------------------------------- static DWORD GetSize(); //------------------------------------------------------------------------------------------------ //Description: // Get the lock count //Parameters: // dwIndex : [in] The index to check. //Return Values: // 0 means there is not the thread to lock the index of object or the index if invalid //Others means the count of lock //--------------------------------------------------------------------------------------------------- static LONG GetLockCount(DWORD dwIndex); //---------------------------------------------------------------------------------------- //Description: // The construct is used for enter the critical section //Parameters: // dwIndex : [in] The index to lock // pRes : [in] The result of locking. TRUE means succeeded, FALSE means failed. // If you don't want this value,you could set NULL. //---------------------------------------------------------------------------------------- CLock(DWORD dwIndex,BOOL *pRes = NULL); //---------------------------------------------------------------------------------------- //Description: // The destruct is used for leave the critical section //---------------------------------------------------------------------------------------- virtual ~CLock(); private: //---------------------------------------------------------------------------------------- //Description: // Add the critical section object to the table. //Parameters: // pcsCriticalSection : [in] The object to add. //Parameters: // Return the index in the table. //-------------------------------------------------------------------------------------- static DWORD AddTable(CRITICAL_SECTION* pcsCriticalSection); //---------------------------------------------------------------------------------------- //Description: // The struct value is for the internal value //---------------------------------------------------------------------------------------- struct CriticalSectionData { CRITICAL_SECTION *pCriticalSection; LONG lLockCount; }; //---------------------------------------------------------------------------------------- //Description: // Delete the object base on the iterator positon //Parameters: // iter : [in] The iterator to delete //----------------------------------------------------------------------------------------- static BOOL Delete(const std::map<DWORD,CriticalSectionData>::iterator &iter); //---------------------------------------------------------------------------------------- //Description: // Get the critical section object //Parameters: // dwIndex : [in] The index to get. //Return Values: // NULL means failed,others is succeeded. //---------------------------------------------------------------------------------------- static CriticalSectionData* GetObject(DWORD dwIndex); //---------------------------------------------------------------------------------------- //Description: // Check and delete the critical section which is allocate by new operate. //---------------------------------------------------------------------------------------- static void CheckAndDeleteCriticalSection(); private: static std::map<DWORD,CriticalSectionData> *ms_pmpCriticalSection; static DWORD ms_dwIndex; CriticalSectionData *m_pcsCriticalSection; };
.cpp实现文件:
#include "Lock.h" //---------------------------------------------------------------------------------- //The static member std::map<DWORD,CLock::CriticalSectionData> * CLock::ms_pmpCriticalSection = NULL; DWORD CLock::ms_dwIndex = 0; //---------------------------------------------------------------------------------- CLock::CLock(DWORD dwIndex,BOOL *pRes): m_pcsCriticalSection(NULL) { //In order to make the source code simple, set the result as FALSE at first. if(pRes != NULL) { *pRes = FALSE; } m_pcsCriticalSection = GetObject(dwIndex); if(m_pcsCriticalSection != NULL) { if(pRes != NULL) { *pRes = TRUE; } InterlockedIncrement(&m_pcsCriticalSection->lLockCount); EnterCriticalSection(m_pcsCriticalSection->pCriticalSection); } } CLock::~CLock() { if(m_pcsCriticalSection != NULL) { LeaveCriticalSection(m_pcsCriticalSection->pCriticalSection); InterlockedDecrement(&m_pcsCriticalSection->lLockCount); } } DWORD CLock::Create() { CRITICAL_SECTION* pcsCriticalSection = new CRITICAL_SECTION(); if(pcsCriticalSection == NULL) { return Lock::INVALID_INDEX; } __try { InitializeCriticalSection(pcsCriticalSection); } __except(GetExceptionCode() == STATUS_NO_MEMORY) { //Failed to intialize the critical section, so delete the object created by new operate. delete pcsCriticalSection; return Lock::INVALID_INDEX; } return AddTable(pcsCriticalSection); } void CLock::DeleteAll() { if(ms_pmpCriticalSection == NULL) { ASSERT(FALSE); return; } for(std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->begin(); iter != ms_pmpCriticalSection->end(); ) { //The iterator would be destroy when you call erase,so I must call just as follows. if(Delete(iter) != FALSE) { ms_pmpCriticalSection->erase(iter ++); } else { ++ iter; } } CheckAndDeleteCriticalSection(); } CLock::CriticalSectionData* CLock::GetObject(DWORD dwIndex) { if(ms_pmpCriticalSection == NULL) { ASSERT(FALSE); return NULL; } std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->find(dwIndex); if(iter != ms_pmpCriticalSection->end()) { return &iter->second; } else { return NULL; } } DWORD CLock::GetSize() { if(ms_pmpCriticalSection == NULL) { ASSERT(FALSE); return 0; } return ms_pmpCriticalSection->size(); } DWORD CLock::AddTable(CRITICAL_SECTION* pcsCriticalSection) { if(ms_pmpCriticalSection == NULL) { ms_pmpCriticalSection = new std::map<DWORD,CriticalSectionData>(); if(ms_pmpCriticalSection == NULL) { return Lock::INVALID_INDEX; } else { ms_dwIndex = 0; } } CriticalSectionData newCriticalSectionData = {pcsCriticalSection,0}; InterlockedIncrement(reinterpret_cast<LONG *>(&ms_dwIndex)); ms_pmpCriticalSection->insert(std::make_pair(ms_dwIndex,newCriticalSectionData)); return ms_dwIndex; } BOOL CLock::Delete(DWORD dwIndex) { if(ms_pmpCriticalSection == NULL) { ASSERT(FALSE); return FALSE; } std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->find(dwIndex); if(Delete(iter) != FALSE) { ms_pmpCriticalSection->erase(iter); CheckAndDeleteCriticalSection(); return TRUE; } else { return FALSE; } } BOOL CLock::Delete(const std::map<DWORD,CriticalSectionData>::iterator &iter) { if(ms_pmpCriticalSection == NULL) { ASSERT(FALSE); return FALSE; } if(iter == ms_pmpCriticalSection->end()) { return FALSE; } if(GetLockCount(iter->first) != 0) { ASSERT(FALSE); return FALSE; } if(iter->second.pCriticalSection == NULL) { return FALSE; } DeleteCriticalSection(iter->second.pCriticalSection); delete iter->second.pCriticalSection; return TRUE; } LONG CLock::GetLockCount(DWORD dwIndex) { CriticalSectionData *pCriticalSection = GetObject(dwIndex); if(pCriticalSection == NULL) { return 0; } else { return pCriticalSection->lLockCount; } } void CLock::CheckAndDeleteCriticalSection() { if(ms_pmpCriticalSection->empty() != FALSE) { delete ms_pmpCriticalSection; ms_pmpCriticalSection = NULL; } }
简单地调用示范如下:
view plain copy to clipboard print ?
-
- const DWORD dwIndex = CLock::Create();
-
-
- CLock lock(dwIndex);
-
-
- CLock::Delete(dwIndex);
//获取相应的序号 const DWORD dwIndex = CLock::Create(); //进入临界区 CLock lock(dwIndex); //删除相应的临界区 CLock::Delete(dwIndex);