如何写优雅的代码(5)——远离临界区噩梦

来源:互联网 发布:如何看待网络信息安全 编辑:程序博客网 时间:2024/06/08 08:34
 

//========================================================================
//TITLE:
//    如何写优雅的代码(5)--远离临界区噩梦
//AUTHOR:
//    norains
//DATE:
//    Tuesday 01- December-2009
//Environment:
//    WINDOWS CE 5.0
//========================================================================

  在平时的多线程编程中,我们往往离不开临界区。会用,甚至是用得好的朋友,估计不少;但用得万无一失的,相对而言,可能就会少很多。
  
  不信?我们来看看下面这段代码:  
  

view plaincopy to clipboardprint?
  1. try  
  2.   {  
  3.     EnterCriticalSection(&g_cs);  
  4.     Cal3rdPartCode(pParam);  
  5.     LeaveCriticalSection(&g_cs);  
  6.   }  
  7.   catch(...)  
  8.   {  
  9.     //There is error   
  10.     //dwRet = 0;   
  11.   }  

 

  这段代码看起来似乎没有什么问题?但如果说,这段代码会引发孤立临界区的问题,你会信么?换句话说,如果Cal3rdPartCode(pParam)函数会抛出异常,那么代码就直接跳转到catch部分。那事情就严重了,因为代码根本就没有调用LeaveCriticalSection(&g_cs),将g_cs这临界区完全孤立了起来,别的线程就只能一直等待该临界区。
  
  似乎情况很糟糕,不是么?当然,糟糕并不代表陷入世界末日,虽然路途上充满了荆棘,但毕竟我们还是能看到阳光。
  
  我们总不能在一棵树上吊死吧。换个角度,临界区的使用,必须是EnterCriticalSection和LeaveCriticalSection配套使用。那么我们想想,C++里面,有什么东西是强制配套的,根本不用使用者干预的?也许有的朋友已经想到了。没错,是类,类的构造函数和析构函数。
  
  正常使用的话,无论使用者愿不愿意,类的构造函数和析构函数都是被编译器强制配套使用。所以,我们可以在构造函数中调用EnterCriticalSection,在析构函数则是LeaveCriticalSection。
  
  根据此思想,我们最简单的用类来调用临界区的代码诞生了:
  

view plaincopy to clipboardprint?
  1.      class CLock  
  2.      {  
  3.        public:  
  4.          CLock(LPCRITICAL_SECTION pCriticalSection):  
  5.          m_ pCriticalSection(pCriticalSection)  
  6.     {  
  7.       EnterCriticalSection(m_ pCriticalSection);  
  8.     };  
  9.       
  10.     virtual ~CLock()  
  11.     {  
  12.       LeaveCriticalSection (m_ pCriticalSection);  
  13.     };  
  14.       
  15.     private:  
  16.       LPCRITICAL_SECTION m_ pCriticalSection;  
  17.      };  
  18.        


  使用上也是简单明了:
  

view plaincopy to clipboardprint?
  1.      void CallFunctionProc()  
  2.      {  
  3.        CLock lock(&g_cs);  
  4.      }  
  5.     


  但这样完美了么?很遗憾,这只是万里长征的第一步,我们的路还很漫长。最根本的问题,我们如何确保传入的临界区指针是有效的?换句话说,我们无法保证传入的临界区指针是没有调用过DeleteCriticalSection的。
  
  如果代码是如下的书写,很明显,肯定会有我们无法预料的异常:
  
view plaincopy to clipboardprint?
  1.  void CallFunctionProc()  
  2.      {  
  3.      DeleteCriticalSection(&g_cs);  
  4.      ...  
  5.        
  6.        CLock lock(&g_cs);  
  7.      }  
  8.     
 
    
  那有没有这么一种机制,我们可以通过它进入临界区,但我们却不能让它删除临界区,或是即使删除了,我们也有足够的信息获知。
  
  万事无绝对,既然我们能想到,那么我们就能做到。人有多大胆,地有多大产,在这个奇迹倍出的IT界,有时候也并不只是一句华而不实的口号。
  
  首先,我们将创建临界区的操作封装于类中,使用者只能获得创建的序号;然后,如果想进入临界区,只要传入序号即可;最后,如果不需要该临界区,那么传入序号删除即可。这样的好处是,通过序号这个桥梁,既能使用临界区的功能,又不会引发临界区的不稳定。
  
  我们先来看看创建的函数:
  
view plaincopy to clipboardprint?
  1. static DWORD CLock::Create()  
  2.      {   
  3.       CRITICAL_SECTION* pcsCriticalSection = new CRITICAL_SECTION();  
  4.       if(pcsCriticalSection == NULL)  
  5.       {  
  6.        return Lock::INVALID_INDEX;  
  7.       }  
  8.         
  9.       __try  
  10.       {  
  11.        InitializeCriticalSection(pcsCriticalSection);  
  12.       }  
  13.       __except(GetExceptionCode() == STATUS_NO_MEMORY)  
  14.       {  
  15.        //Failed to intialize the critical section, so delete the object created by new operate.  
  16.        
  17.        delete pcsCriticalSection;  
  18.        
  19.        return Lock::INVALID_INDEX;  
  20.       }  
  21.        
  22.       return AddTable(pcsCriticalSection);   
  23.      }  
  24.     
 
    
  虽然我们将Create函数封装于CLock类中,但我们不打算需要通过对象才能调用,所以我们以static进行修饰,让其成为类函数。那么,我们调用的时候,就可以直接通过类作用域使用:
  
    
view plaincopy to clipboardprint?
  1. DWORD dwIndex = CLock::Create();  

  
  我们留意一下这句:
  
view plaincopy to clipboardprint?
  1. CRITICAL_SECTION* pcsCriticalSection = new CRITICAL_SECTION();  
 
       
  这句代码用来在栈中创建CRITICAL_SECTION对象。之所以这么做,是因为如果使用局部变量,那么在函数返回时,局部变量就被删除。而通过new创建出来的对象,除非我们调用delete,否则在程序运行期中一直存在。这样就能达到创建的目的。
  
  接下来的异常捕获部分可能是大家都会忽略的。根据MSDN的文档,InitializeCriticalSection并不保证绝对能创建成功。当内存不足时,就会抛出STATUS_NO_MEMORY异常。所以我们必须捕获这个异常,并进行相应的处理。
  
  话又说回来,在我们平时直接调用临界区的方式中,如果出现这个异常是很麻烦的事情。因为CRITICAL_SECTION对象的内部细节没有公布,我们无法根据CRITICAL_SECTION对象来确定临界区是否有效,也就无法保证代码的健壮性。
  
  如果一切顺利,我们就通过AddTable将临界区放入存储空间中。
  
  AddTable的实现如下:
  
view plaincopy to clipboardprint?
  1. static DWORD CLock::AddTable(CRITICAL_SECTION* pcsCriticalSection)  
  2.      {   
  3.       if(ms_pmpCriticalSection == NULL)  
  4.       {  
  5.        ms_pmpCriticalSection = new std::map<DWORD,CriticalSectionData>();  
  6.          
  7.        if(ms_pmpCriticalSection == NULL)  
  8.        {  
  9.         return Lock::INVALID_INDEX;  
  10.        }  
  11.        else  
  12.        {  
  13.         ms_dwIndex = 0;  
  14.        }    
  15.       }  
  16.        
  17.       CriticalSectionData newCriticalSectionData = {pcsCriticalSection,0};  
  18.       InterlockedIncrement(reinterpret_cast<LONG *>(&ms_dwIndex));  
  19.       ms_pmpCriticalSection->insert(std::make_pair(ms_dwIndex,newCriticalSectionData));  
  20.        
  21.       return ms_dwIndex;  
  22.      }  
  23.     
 
    
  ms_pmpCriticalSection是一个成员变量指针,其在头文件声明如下:
  
  
view plaincopy to clipboardprint?
  1. static std::map<DWORD,CriticalSectionData> *ms_pmpCriticalSection;  

  
  CriticalSectionData是我们定义的一个结构体,有两个成员变量,一个是指向临界区对象,另一个则记录了进入该临界区的次数:  
    
view plaincopy to clipboardprint?
  1. struct CriticalSectionData  
  2.      {  
  3.       CRITICAL_SECTION *pCriticalSection;  
  4.       LONG lLockCount;  
  5.      };  

  
  看到这里,可能有的朋友说,CRITICAL_SECTION不是有个LockCount成员么,直接使用它不就行了?从理论上来说,这是可以的。但对于该结构,微软并没有描述文档,换而言之,微软保留了变更其成员的权利。虽然我们可以相信,微软一般不会做这种费力不讨好的事,但谁知道哪天微软又心血来潮呢?所以,与其将代码建立于微软的信任,还不如建立于我们的掌握之中。
  
  我们稍微回头看看,为什么我们定义ms_pmpCriticalSection为指针,而不是直接作为普通变量?也就是说,为什么不直接这样定义:
  
view plaincopy to clipboardprint?
  1. static std::map<DWORD,CriticalSectionData> ms_mpCriticalSection;  
 
       
  如果这样定义,会有很大的风险。因为如果有一个类在构造函数调用了CLock::Create,而该类之后的对象又有一个静态声明,那么就会涉及到静态变量初始化顺序的不可控问题。因为在你调用CLock::Create的时候,ms_mpCriticalSection对象很有可能还有进行初始化。
  
  例如:
     
view plaincopy to clipboardprint?
  1. class CTest  
  2.      {  
  3.        public:  
  4.         CText():  
  5.         m_dwLock(CLock::Create())  
  6.      {  
  7.      }  
  8.        
  9.      private:  
  10.      DWORD m_dwLock;  
  11.      };  
    
    
    
view plaincopy to clipboardprint?
  1. //这里很可能会出错,因为其构造函数调用了CLock::Create,而ms_mpCriticalSection很可能还没有进行初始化  
  2.      static CTest test;  
  


  为了避免静态变量初始化导致的问题,我们只能采用new来进行分配。
  
  在这里还有一个小技巧,为了避免繁琐的算法,我们直接采用了STL的map。这样,在后续的查找中,我们就能比较轻松。
  
  既然返回的只是序号,那么我们的构造函数也必然需要进行相应的修改:
  

view plaincopy to clipboardprint?
  1. CLock::CLock(DWORD dwIndex,BOOL *pRes = NULL):  
  2.      m_pcsCriticalSection(NULL)  
  3.      {  
  4.       //In order to make the source code simple, set the result as FALSE at first.  
  5.       if(pRes != NULL)  
  6.       {  
  7.        *pRes = FALSE;  
  8.       }  
  9.         
  10.       m_pcsCriticalSection = GetObject(dwIndex);  
  11.       if(m_pcsCriticalSection != NULL)  
  12.       {  
  13.        if(pRes != NULL)  
  14.        {  
  15.         *pRes = TRUE;  
  16.        }  
  17.          
  18.        InterlockedIncrement(&m_pcsCriticalSection->lLockCount);  
  19.        EnterCriticalSection(m_pcsCriticalSection->pCriticalSection);  
  20.       }   
  21.      }  
  22.     
 
    
  从使用角度来说,我们只需要一个序号的形参即可。但我们想知道能不能成功进入临界区,而构造函数又不能拥有返回值,所以我们就额外多增加了一个pRes形参,用来在函数返回后指明当前进入临界区的状况。
  
  GetObject是我们定义的一个函数,具体实现将在后面说明。现在只需要知道其实返回创建的一个临界区数据。如果获取一个临界区数据对象不为NULL,那么我们在进入临界区之前,先将lLockCount的计数增加1,标明当前进入临界区的次数。
  
  其实很简单,和之前我们的最简单的构造函数相比,只是传入的形参不同。而恰恰只是这一点不同,就能使我们的代码临界区有一个质的飞跃。
  
  再转回头,我们看看GetObject的实现:
    
view plaincopy to clipboardprint?
  1. CLock::CriticalSectionData* CLock::GetObject(DWORD dwIndex)  
  2. {  
  3.  if(ms_pmpCriticalSection == NULL)  
  4.  {  
  5.   ASSERT(FALSE);  
  6.   return NULL;  
  7.  }  
  8.   
  9.  std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->find(dwIndex);  
  10.  if(iter != ms_pmpCriticalSection->end())  
  11.  {  
  12.   return &iter->second;    
  13.  }  
  14.  else  
  15.  {  
  16.   return NULL;  
  17.  }  
  18.   
  19. }  


  代码并不复杂,只是从ms_pmpCriticalSection搜索出对应序号的数值,然后返回。如果该序号不存在,则返回NULL。
  
  到这里,使用上的功能我们基本上已经完成。但似乎还缺了点什么,对,没错,还缺删除函数。删除函数并不复杂,删除临界区后,然后调用delete删除创建的栈,最后再从ms_pmpCriticalSection中删掉相应的序号即可。但我们需要考虑到使用者的便利性,不仅可以删除对应序号的对象,还能简单地删除所有。所以,对于删除函数,我们定义两个。而这两个删除函数,都应该通过不同的手法调用这个内部删除函数:
  

view plaincopy to clipboardprint?
  1.  static BOOL CLock::Delete(const std::map<DWORD,CriticalSectionData>::iterator &iter)  
  2.      {  
  3.       if(ms_pmpCriticalSection == NULL)  
  4.       {  
  5.        ASSERT(FALSE);  
  6.        return FALSE;  
  7.       }  
  8.        
  9.       if(iter == ms_pmpCriticalSection->end())  
  10.       {  
  11.        return FALSE;  
  12.       }  
  13.        
  14.       if(GetLockCount(iter->first) != 0)  
  15.       {    
  16.        ASSERT(FALSE);  
  17.        return FALSE;  
  18.       }   
  19.        
  20.       if(iter->second.pCriticalSection == NULL)  
  21.       {  
  22.        return FALSE;  
  23.       }  
  24.        
  25.       DeleteCriticalSection(iter->second.pCriticalSection);  
  26.       delete iter->second.pCriticalSection;   
  27.        
  28.       return TRUE;  
  29.      }  
  30.     
 
    
  形参是传入一个迭代器,然后根据该迭代器做相应的操作。
  
  那么,我们public的删除相应序号的函数可以如下:  
    
view plaincopy to clipboardprint?
  1. BOOL CLock::Delete(DWORD dwIndex)  
  2.     {  
  3.      if(ms_pmpCriticalSection == NULL)  
  4.      {  
  5.       ASSERT(FALSE);  
  6.       return FALSE;  
  7.      }  
  8.       
  9.      std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->find(dwIndex);  
  10.      if(Delete(iter) != FALSE)  
  11.      {  
  12.       ms_pmpCriticalSection->erase(iter);  
  13.       
  14.       CheckAndDeleteCriticalSection();  
  15.       
  16.       return TRUE;  
  17.      }  
  18.      else  
  19.      {  
  20.       return FALSE;  
  21.      }  
  22.       
  23.     }  
  24.    

  函数过程简单明了,从通过find函数查找相应key的位置,然后传递给Delete函数。如果Delete返回值为TRUE,那么我们就通过erase擦除。我们之所以没有在Delete(const std::map<DWORD,CriticalSectionData>::iterator &iter)函数中进行擦除,是因为map的迭代器,只要一删除,就会失效,这对后续的操作有所不利。所以,我们只能根据其返回值再确定是否删除。
  
  CheckAndDeleteCriticalSection()函数用来判断ms_pmpCriticalSection是否为空,如果为空,直接调用delete删除该指针:  
    
view plaincopy to clipboardprint?
  1. static void CLock::CheckAndDeleteCriticalSection()  
  2.      {  
  3.       if(ms_pmpCriticalSection->empty() != FALSE)  
  4.       {  
  5.        delete ms_pmpCriticalSection;  
  6.        ms_pmpCriticalSection = NULL;  
  7.       }  
  8.      }  

  
  有了这些基础,那么我们的删除所有的函数就简单了:
  
view plaincopy to clipboardprint?
  1. static void CLock::DeleteAll()  
  2.     {  
  3.      if(ms_pmpCriticalSection == NULL)  
  4.      {  
  5.       ASSERT(FALSE);  
  6.       return;  
  7.      }  
  8.       
  9.      for(std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->begin(); iter != ms_pmpCriticalSection->end(); )  
  10.      {  
  11.       //The iterator would be destroy when you call erase,so I must call just as follows.  
  12.       if(Delete(iter) != FALSE)  
  13.       {  
  14.        ms_pmpCriticalSection->erase(iter ++);  
  15.       }  
  16.       else  
  17.       {  
  18.        ++ iter;  
  19.       }  
  20.      }   
  21.       
  22.      CheckAndDeleteCriticalSection();  
  23.       
  24.     }  
  25.    
 
    
  首先我们判断ms_pmpCriticalSection是否为NULL,为NULL则什么都不做,返回。然后,再遍历整个存储空间,传入其相应的迭代器进行操作。如果Delete返回不为FALSE,我们就调用erase进行删除。
  
  在这里一个小细节需要留意,就是这段代码:
  
view plaincopy to clipboardprint?
  1. for(std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->begin(); iter != ms_pmpCriticalSection->end(); )  
  2.       {  
  3.        //The iterator would be destroy when you call erase,so I must call just as follows.  
  4.        if(Delete(iter) != FALSE)  
  5.        {  
  6.         ms_pmpCriticalSection->erase(iter ++);  
  7.        }  
  8.        else  
  9.        {  
  10.         ++ iter;  
  11.        }  
  12.       }   
  13.        
 
    
  对于这段代码,我们不能这么改写:
  
view plaincopy to clipboardprint?
  1. for(std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->begin(); iter != ms_pmpCriticalSection->end();++ iter )  
  2.       {  
  3.        //The iterator would be destroy when you call erase,so I must call just as follows.  
  4.        if(Delete(iter) != FALSE)  
  5.        {  
  6.         ms_pmpCriticalSection->erase(iter);  
  7.        }  
  8.          
  9.       }  
 
    
  因为我们知道,map容器只要进行erase操作,那么相应的迭代器就会失效。如果采用的是后面一种写法,那么我们调用erase操作后,iter就已经无效,循环中的iter就变成一个不可预料的操作。
  
  现在,就是完整罗列代码的时候了:
  
  头文件:
  
view plaincopy to clipboardprint?
  1. #pragma once   
  2.        
  3.      #include "Windows.h"  
  4.      #include <map>   
  5.        
  6.      namespace Lock  
  7.      {  
  8.       const DWORD INVALID_INDEX = 0xFFFFFFFF;  
  9.      };  
  10.        
  11.      class CLock  
  12.      {  
  13.      public:  
  14.       //----------------------------------------------------------------------------------------  
  15.       //Description:   
  16.       //   Create the lock object and return the index  
  17.       //Return Values:   
  18.       // If the value is INVALID_INDEX, it means failed. Others is succeeded.  
  19.       //-----------------------------------------------------------------------------------------  
  20.       static DWORD Create();  
  21.        
  22.       //---------------------------------------------------------------------------------------------  
  23.       //Description:   
  24.       //   Delete all the created critical section.When you call the function,you must be sure that  
  25.       //there isn't other threads to enter the critical section.After succeed in calling the function,  
  26.       //the GetSize() returns 0, otherwise it doesn't delete all the critical section object.  
  27.       //---------------------------------------------------------------------------------------------  
  28.       static void DeleteAll();   
  29.        
  30.       //---------------------------------------------------------------------------------------------  
  31.       //Description:   
  32.       //   Delete the created critical section on the index.  
  33.       //Parameters:   
  34.       // dwIndex : [in]The index of object to delete  
  35.       //Return Values:   
  36.       // FALSE means failed, maybe the index is locked.  
  37.       //---------------------------------------------------------------------------------------------  
  38.       static BOOL Delete(DWORD dwIndex);   
  39.        
  40.       //----------------------------------------------------------------------------------------  
  41.       //Description:   
  42.       //   Get the size of the the critical section  
  43.       //----------------------------------------------------------------------------------------  
  44.       static DWORD GetSize();  
  45.        
  46.       //------------------------------------------------------------------------------------------------  
  47.       //Description:   
  48.       //   Get the lock count   
  49.       //Parameters:   
  50.       // dwIndex : [in] The index to check.  
  51.       //Return Values:   
  52.       // 0 means there is not the thread to lock the index of object or the index if invalid  
  53.       //Others means the count of lock  
  54.       //---------------------------------------------------------------------------------------------------  
  55.       static LONG GetLockCount(DWORD dwIndex);  
  56.        
  57.       //----------------------------------------------------------------------------------------  
  58.       //Description:   
  59.       //   The construct is used for enter the critical section  
  60.       //Parameters:   
  61.       // dwIndex : [in] The index to lock  
  62.       // pRes : [in] The result of locking. TRUE means succeeded, FALSE means failed.  
  63.       //    If you don't want this value,you could set NULL.  
  64.       //----------------------------------------------------------------------------------------  
  65.       CLock(DWORD dwIndex,BOOL *pRes = NULL);  
  66.        
  67.       //----------------------------------------------------------------------------------------  
  68.       //Description:   
  69.       //   The destruct is used for leave the critical section  
  70.       //----------------------------------------------------------------------------------------  
  71.       virtual ~CLock();  
  72.        
  73.      private:  
  74.       //----------------------------------------------------------------------------------------  
  75.       //Description:   
  76.       //   Add the critical section object to the table.  
  77.       //Parameters:   
  78.       // pcsCriticalSection : [in] The object to add.  
  79.       //Parameters:   
  80.       // Return the index in the table.   
  81.       //--------------------------------------------------------------------------------------  
  82.       static DWORD AddTable(CRITICAL_SECTION* pcsCriticalSection);  
  83.        
  84.        
  85.       //----------------------------------------------------------------------------------------  
  86.       //Description:   
  87.       //  The struct value is for the internal value  
  88.       //----------------------------------------------------------------------------------------  
  89.       struct CriticalSectionData  
  90.       {  
  91.        CRITICAL_SECTION *pCriticalSection;  
  92.        LONG lLockCount;  
  93.       };  
  94.        
  95.       //----------------------------------------------------------------------------------------  
  96.       //Description:   
  97.       //  Delete the object base on the iterator positon  
  98.       //Parameters:   
  99.       // iter : [in] The iterator to delete  
  100.       //-----------------------------------------------------------------------------------------  
  101.       static BOOL Delete(const std::map<DWORD,CriticalSectionData>::iterator &iter);  
  102.        
  103.       //----------------------------------------------------------------------------------------  
  104.       //Description:   
  105.       //   Get the critical section object  
  106.       //Parameters:   
  107.       // dwIndex : [in] The index to get.  
  108.       //Return Values:   
  109.       // NULL means failed,others is succeeded.  
  110.       //----------------------------------------------------------------------------------------  
  111.       static CriticalSectionData* GetObject(DWORD dwIndex);  
  112.        
  113.       //----------------------------------------------------------------------------------------  
  114.       //Description:   
  115.       //   Check and delete the critical section which is allocate by new operate.  
  116.       //----------------------------------------------------------------------------------------  
  117.       static void CheckAndDeleteCriticalSection();  
  118.        
  119.      private:   
  120.       static std::map<DWORD,CriticalSectionData> *ms_pmpCriticalSection;  
  121.       static DWORD ms_dwIndex;  
  122.       CriticalSectionData *m_pcsCriticalSection;  
  123.      };  
  124.     

  
  .cpp实现文件:
  
view plaincopy to clipboardprint?
  1.   #include "Lock.h"  
  2.        
  3.      //----------------------------------------------------------------------------------  
  4.      //The static member   
  5.      std::map<DWORD,CLock::CriticalSectionData> * CLock::ms_pmpCriticalSection = NULL;  
  6.      DWORD CLock::ms_dwIndex = 0;  
  7.      //----------------------------------------------------------------------------------  
  8.        
  9.      CLock::CLock(DWORD dwIndex,BOOL *pRes):  
  10.      m_pcsCriticalSection(NULL)  
  11.      {  
  12.       //In order to make the source code simple, set the result as FALSE at first.  
  13.       if(pRes != NULL)  
  14.       {  
  15.        *pRes = FALSE;  
  16.       }  
  17.         
  18.       m_pcsCriticalSection = GetObject(dwIndex);  
  19.       if(m_pcsCriticalSection != NULL)  
  20.       {  
  21.        if(pRes != NULL)  
  22.        {  
  23.         *pRes = TRUE;  
  24.        }  
  25.          
  26.        InterlockedIncrement(&m_pcsCriticalSection->lLockCount);  
  27.        EnterCriticalSection(m_pcsCriticalSection->pCriticalSection);  
  28.       }   
  29.      }  
  30.        
  31.      CLock::~CLock()  
  32.      {  
  33.       if(m_pcsCriticalSection != NULL)  
  34.       {  
  35.        LeaveCriticalSection(m_pcsCriticalSection->pCriticalSection);  
  36.        InterlockedDecrement(&m_pcsCriticalSection->lLockCount);  
  37.       }  
  38.      }  
  39.        
  40.      DWORD CLock::Create()  
  41.      {   
  42.       CRITICAL_SECTION* pcsCriticalSection = new CRITICAL_SECTION();  
  43.       if(pcsCriticalSection == NULL)  
  44.       {  
  45.        return Lock::INVALID_INDEX;  
  46.       }  
  47.         
  48.       __try  
  49.       {  
  50.        InitializeCriticalSection(pcsCriticalSection);  
  51.       }  
  52.       __except(GetExceptionCode() == STATUS_NO_MEMORY)  
  53.       {  
  54.        //Failed to intialize the critical section, so delete the object created by new operate.  
  55.        
  56.        delete pcsCriticalSection;  
  57.        
  58.        return Lock::INVALID_INDEX;  
  59.       }  
  60.        
  61.       return AddTable(pcsCriticalSection);   
  62.      }  
  63.        
  64.      void CLock::DeleteAll()  
  65.      {  
  66.       if(ms_pmpCriticalSection == NULL)  
  67.       {  
  68.        ASSERT(FALSE);  
  69.        return;  
  70.       }  
  71.        
  72.       for(std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->begin(); iter != ms_pmpCriticalSection->end(); )  
  73.       {  
  74.        //The iterator would be destroy when you call erase,so I must call just as follows.  
  75.        if(Delete(iter) != FALSE)  
  76.        {  
  77.         ms_pmpCriticalSection->erase(iter ++);  
  78.        }  
  79.        else  
  80.        {  
  81.         ++ iter;  
  82.        }  
  83.       }   
  84.        
  85.       CheckAndDeleteCriticalSection();  
  86.        
  87.      }  
  88.        
  89.      CLock::CriticalSectionData* CLock::GetObject(DWORD dwIndex)  
  90.      {  
  91.       if(ms_pmpCriticalSection == NULL)  
  92.       {  
  93.        ASSERT(FALSE);  
  94.        return NULL;  
  95.       }  
  96.        
  97.       std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->find(dwIndex);  
  98.       if(iter != ms_pmpCriticalSection->end())  
  99.       {  
  100.        return &iter->second;    
  101.       }  
  102.       else  
  103.       {  
  104.        return NULL;  
  105.       }  
  106.        
  107.      }  
  108.        
  109.      DWORD CLock::GetSize()  
  110.      {  
  111.       if(ms_pmpCriticalSection == NULL)  
  112.       {  
  113.        ASSERT(FALSE);  
  114.        return 0;  
  115.       }  
  116.        
  117.       return ms_pmpCriticalSection->size();  
  118.      }  
  119.        
  120.        
  121.        
  122.      DWORD CLock::AddTable(CRITICAL_SECTION* pcsCriticalSection)  
  123.      {   
  124.       if(ms_pmpCriticalSection == NULL)  
  125.       {  
  126.        ms_pmpCriticalSection = new std::map<DWORD,CriticalSectionData>();  
  127.          
  128.        if(ms_pmpCriticalSection == NULL)  
  129.        {  
  130.         return Lock::INVALID_INDEX;  
  131.        }  
  132.        else  
  133.        {  
  134.         ms_dwIndex = 0;  
  135.        }    
  136.       }  
  137.        
  138.       CriticalSectionData newCriticalSectionData = {pcsCriticalSection,0};  
  139.       InterlockedIncrement(reinterpret_cast<LONG *>(&ms_dwIndex));  
  140.       ms_pmpCriticalSection->insert(std::make_pair(ms_dwIndex,newCriticalSectionData));  
  141.        
  142.       return ms_dwIndex;  
  143.      }  
  144.        
  145.      BOOL CLock::Delete(DWORD dwIndex)  
  146.      {  
  147.       if(ms_pmpCriticalSection == NULL)  
  148.       {  
  149.        ASSERT(FALSE);  
  150.        return FALSE;  
  151.       }  
  152.        
  153.       std::map<DWORD,CriticalSectionData>::iterator iter = ms_pmpCriticalSection->find(dwIndex);  
  154.       if(Delete(iter) != FALSE)  
  155.       {  
  156.        ms_pmpCriticalSection->erase(iter);  
  157.        
  158.        CheckAndDeleteCriticalSection();  
  159.        
  160.        return TRUE;  
  161.       }  
  162.       else  
  163.       {  
  164.        return FALSE;  
  165.       }  
  166.        
  167.      }  
  168.        
  169.      BOOL CLock::Delete(const std::map<DWORD,CriticalSectionData>::iterator &iter)  
  170.      {  
  171.       if(ms_pmpCriticalSection == NULL)  
  172.       {  
  173.        ASSERT(FALSE);  
  174.        return FALSE;  
  175.       }  
  176.        
  177.       if(iter == ms_pmpCriticalSection->end())  
  178.       {  
  179.        return FALSE;  
  180.       }  
  181.        
  182.       if(GetLockCount(iter->first) != 0)  
  183.       {    
  184.        ASSERT(FALSE);  
  185.        return FALSE;  
  186.       }   
  187.        
  188.       if(iter->second.pCriticalSection == NULL)  
  189.       {  
  190.        return FALSE;  
  191.       }  
  192.        
  193.       DeleteCriticalSection(iter->second.pCriticalSection);  
  194.       delete iter->second.pCriticalSection;   
  195.        
  196.       return TRUE;  
  197.      }  
  198.        
  199.      LONG CLock::GetLockCount(DWORD dwIndex)  
  200.      {  
  201.       CriticalSectionData *pCriticalSection = GetObject(dwIndex);  
  202.       if(pCriticalSection == NULL)  
  203.       {  
  204.        return 0;  
  205.       }  
  206.       else  
  207.       {  
  208.        return pCriticalSection->lLockCount;  
  209.       }  
  210.      }  
  211.        
  212.      void CLock::CheckAndDeleteCriticalSection()  
  213.      {  
  214.       if(ms_pmpCriticalSection->empty() != FALSE)  
  215.       {  
  216.        delete ms_pmpCriticalSection;  
  217.        ms_pmpCriticalSection = NULL;  
  218.       }  
  219.      }  
  220.     


  简单地调用示范如下:
  

view plaincopy to clipboardprint?
  1. //获取相应的序号   
  2. const DWORD dwIndex = CLock::Create();  
  3.   
  4. //进入临界区   
  5. CLock lock(dwIndex);  
  6.   
  7. //删除相应的临界区   
  8. CLock::Delete(dwIndex);  

原创粉丝点击