日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時間:2023/12/20 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何写优雅的代码(5)——远离临界区噩梦 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

//========================================================================
//TITLE:
// 如何寫優(yōu)雅的代碼(5)--遠離臨界區(qū)噩夢
//AUTHOR:
// norains
//DATE:
// Tuesday 01- December-2009
//Environment:
// WINDOWS CE 5.0
//========================================================================

  在平時的多線程編程中,我們往往離不開臨界區(qū)。會用,甚至是用得好的朋友,估計不少;但用得萬無一失的,相對而言,可能就會少很多。
  
  不信?我們來看看下面這段代碼:  
  try   {    EnterCriticalSection(&g_cs);    Cal3rdPartCode(pParam);    LeaveCriticalSection(&g_cs);   }   catch(...)   {    //There is error    //dwRet = 0;   }

  這段代碼看起來似乎沒有什么問題?但如果說,這段代碼會引發(fā)孤立臨界區(qū)的問題,你會信么?換句話說,如果Cal3rdPartCode(pParam)函數(shù)會拋出異常,那么代碼就直接跳轉(zhuǎn)到catch部分。那事情就嚴重了,因為代碼根本就沒有調(diào)用LeaveCriticalSection(&g_cs),將g_cs這臨界區(qū)完全孤立了起來,別的線程就只能一直等待該臨界區(qū)。
  
  似乎情況很糟糕,不是么?當然,糟糕并不代表陷入世界末日,雖然路途上充滿了荊棘,但畢竟我們還是能看到陽光。
  
  我們總不能在一棵樹上吊死吧。換個角度,臨界區(qū)的使用,必須是EnterCriticalSection和LeaveCriticalSection配套使用。那么我們想想,C++里面,有什么東西是強制配套的,根本不用使用者干預的?也許有的朋友已經(jīng)想到了。沒錯,是類,類的構(gòu)造函數(shù)和析構(gòu)函數(shù)。
  
  正常使用的話,無論使用者愿不愿意,類的構(gòu)造函數(shù)和析構(gòu)函數(shù)都是被編譯器強制配套使用。所以,我們可以在構(gòu)造函數(shù)中調(diào)用EnterCriticalSection,在析構(gòu)函數(shù)則是LeaveCriticalSection。
  
  根據(jù)此思想,我們最簡單的用類來調(diào)用臨界區(qū)的代碼誕生了:
   class CLock { public: CLock(LPCRITICAL_SECTION pCriticalSection): m_ pCriticalSection(pCriticalSection)     {      EnterCriticalSection(m_ pCriticalSection);     };          virtual ~CLock()     {      LeaveCriticalSection (m_ pCriticalSection);     };          private:      LPCRITICAL_SECTION m_ pCriticalSection; };


  使用上也是簡單明了:
   void CallFunctionProc() { CLock lock(&g_cs); }   

  但這樣完美了么?很遺憾,這只是萬里長征的第一步,我們的路還很漫長。最根本的問題,我們?nèi)绾未_保傳入的臨界區(qū)指針是有效的?換句話說,我們無法保證傳入的臨界區(qū)指針是沒有調(diào)用過DeleteCriticalSection的。
  
  如果代碼是如下的書寫,很明顯,肯定會有我們無法預料的異常:
   void CallFunctionProc() { DeleteCriticalSection(&g_cs); ... CLock lock(&g_cs); }   

  那有沒有這么一種機制,我們可以通過它進入臨界區(qū),但我們卻不能讓它刪除臨界區(qū),或是即使刪除了,我們也有足夠的信息獲知。
  
  萬事無絕對,既然我們能想到,那么我們就能做到。人有多大膽,地有多大產(chǎn),在這個奇跡倍出的IT界,有時候也并不只是一句華而不實的口號。
  
  首先,我們將創(chuàng)建臨界區(qū)的操作封裝于類中,使用者只能獲得創(chuàng)建的序號;然后,如果想進入臨界區(qū),只要傳入序號即可;最后,如果不需要該臨界區(qū),那么傳入序號刪除即可。這樣的好處是,通過序號這個橋梁,既能使用臨界區(qū)的功能,又不會引發(fā)臨界區(qū)的不穩(wěn)定。
  
  我們先來看看創(chuàng)建的函數(shù):
  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函數(shù)封裝于CLock類中,但我們不打算需要通過對象才能調(diào)用,所以我們以static進行修飾,讓其成為類函數(shù)。那么,我們調(diào)用的時候,就可以直接通過類作用域使用:
  
DWORD dwIndex = CLock::Create();
  
  我們留意一下這句:
  CRITICAL_SECTION* pcsCriticalSection = new CRITICAL_SECTION();
  
  這句代碼用來在棧中創(chuàng)建CRITICAL_SECTION對象。之所以這么做,是因為如果使用局部變量,那么在函數(shù)返回時,局部變量就被刪除。而通過new創(chuàng)建出來的對象,除非我們調(diào)用delete,否則在程序運行期中一直存在。這樣就能達到創(chuàng)建的目的。
  
  接下來的異常捕獲部分可能是大家都會忽略的。根據(jù)MSDN的文檔,InitializeCriticalSection并不保證絕對能創(chuàng)建成功。當內(nèi)存不足時,就會拋出STATUS_NO_MEMORY異常。所以我們必須捕獲這個異常,并進行相應(yīng)的處理。
  
  話又說回來,在我們平時直接調(diào)用臨界區(qū)的方式中,如果出現(xiàn)這個異常是很麻煩的事情。因為CRITICAL_SECTION對象的內(nèi)部細節(jié)沒有公布,我們無法根據(jù)CRITICAL_SECTION對象來確定臨界區(qū)是否有效,也就無法保證代碼的健壯性。
  
  如果一切順利,我們就通過AddTable將臨界區(qū)放入存儲空間中。
  
  AddTable的實現(xiàn)如下:
  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是一個成員變量指針,其在頭文件聲明如下:
  
  static std::map<DWORD,CriticalSectionData> *ms_pmpCriticalSection;
  
  CriticalSectionData是我們定義的一個結(jié)構(gòu)體,有兩個成員變量,一個是指向臨界區(qū)對象,另一個則記錄了進入該臨界區(qū)的次數(shù):  
struct CriticalSectionData { CRITICAL_SECTION *pCriticalSection; LONG lLockCount; };
  
  看到這里,可能有的朋友說,CRITICAL_SECTION不是有個LockCount成員么,直接使用它不就行了?從理論上來說,這是可以的。但對于該結(jié)構(gòu),微軟并沒有描述文檔,換而言之,微軟保留了變更其成員的權(quán)利。雖然我們可以相信,微軟一般不會做這種費力不討好的事,但誰知道哪天微軟又心血來潮呢?所以,與其將代碼建立于微軟的信任,還不如建立于我們的掌握之中。
  
  我們稍微回頭看看,為什么我們定義ms_pmpCriticalSection為指針,而不是直接作為普通變量?也就是說,為什么不直接這樣定義:
  static std::map<DWORD,CriticalSectionData> ms_mpCriticalSection;
  
  如果這樣定義,會有很大的風險。因為如果有一個類在構(gòu)造函數(shù)調(diào)用了CLock::Create,而該類之后的對象又有一個靜態(tài)聲明,那么就會涉及到靜態(tài)變量初始化順序的不可控問題。因為在你調(diào)用CLock::Create的時候,ms_mpCriticalSection對象很有可能還有進行初始化。
  
  例如:
class CTest { public: CText(): m_dwLock(CLock::Create()) { } private: DWORD m_dwLock; };
    
//這里很可能會出錯,因為其構(gòu)造函數(shù)調(diào)用了CLock::Create,而ms_mpCriticalSection很可能還沒有進行初始化 static CTest test;   


  為了避免靜態(tài)變量初始化導致的問題,我們只能采用new來進行分配。
  
  在這里還有一個小技巧,為了避免繁瑣的算法,我們直接采用了STL的map。這樣,在后續(xù)的查找中,我們就能比較輕松。
  
  既然返回的只是序號,那么我們的構(gòu)造函數(shù)也必然需要進行相應(yīng)的修改:
  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); } }   

  從使用角度來說,我們只需要一個序號的形參即可。但我們想知道能不能成功進入臨界區(qū),而構(gòu)造函數(shù)又不能擁有返回值,所以我們就額外多增加了一個pRes形參,用來在函數(shù)返回后指明當前進入臨界區(qū)的狀況。
  
  GetObject是我們定義的一個函數(shù),具體實現(xiàn)將在后面說明。現(xiàn)在只需要知道其實返回創(chuàng)建的一個臨界區(qū)數(shù)據(jù)。如果獲取一個臨界區(qū)數(shù)據(jù)對象不為NULL,那么我們在進入臨界區(qū)之前,先將lLockCount的計數(shù)增加1,標明當前進入臨界區(qū)的次數(shù)。
  
  其實很簡單,和之前我們的最簡單的構(gòu)造函數(shù)相比,只是傳入的形參不同。而恰恰只是這一點不同,就能使我們的代碼臨界區(qū)有一個質(zhì)的飛躍。
  
  再轉(zhuǎn)回頭,我們看看GetObject的實現(xiàn):
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搜索出對應(yīng)序號的數(shù)值,然后返回。如果該序號不存在,則返回NULL。
  
  到這里,使用上的功能我們基本上已經(jīng)完成。但似乎還缺了點什么,對,沒錯,還缺刪除函數(shù)。刪除函數(shù)并不復雜,刪除臨界區(qū)后,然后調(diào)用delete刪除創(chuàng)建的棧,最后再從ms_pmpCriticalSection中刪掉相應(yīng)的序號即可。但我們需要考慮到使用者的便利性,不僅可以刪除對應(yīng)序號的對象,還能簡單地刪除所有。所以,對于刪除函數(shù),我們定義兩個。而這兩個刪除函數(shù),都應(yīng)該通過不同的手法調(diào)用這個內(nèi)部刪除函數(shù):
   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; }   

  形參是傳入一個迭代器,然后根據(jù)該迭代器做相應(yīng)的操作。
  
  那么,我們public的刪除相應(yīng)序號的函數(shù)可以如下:  
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; } }   
  函數(shù)過程簡單明了,從通過find函數(shù)查找相應(yīng)key的位置,然后傳遞給Delete函數(shù)。如果Delete返回值為TRUE,那么我們就通過erase擦除。我們之所以沒有在Delete(const std::map<DWORD,CriticalSectionData>::iterator &iter)函數(shù)中進行擦除,是因為map的迭代器,只要一刪除,就會失效,這對后續(xù)的操作有所不利。所以,我們只能根據(jù)其返回值再確定是否刪除。
  
  CheckAndDeleteCriticalSection()函數(shù)用來判斷ms_pmpCriticalSection是否為空,如果為空,直接調(diào)用delete刪除該指針:  
static void CLock::CheckAndDeleteCriticalSection() { if(ms_pmpCriticalSection->empty() != FALSE) { delete ms_pmpCriticalSection; ms_pmpCriticalSection = NULL; } }
  
  有了這些基礎(chǔ),那么我們的刪除所有的函數(shù)就簡單了:
   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則什么都不做,返回。然后,再遍歷整個存儲空間,傳入其相應(yīng)的迭代器進行操作。如果Delete返回不為FALSE,我們就調(diào)用erase進行刪除。
  
  在這里一個小細節(jié)需要留意,就是這段代碼:
  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; } }

  對于這段代碼,我們不能這么改寫:
  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操作,那么相應(yīng)的迭代器就會失效。如果采用的是后面一種寫法,那么我們調(diào)用erase操作后,iter就已經(jīng)無效,循環(huán)中的iter就變成一個不可預料的操作。
  
  現(xiàn)在,就是完整羅列代碼的時候了:
  
  頭文件:
  #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實現(xiàn)文件:
    #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; } }   


  簡單地調(diào)用示范如下:
   //獲取相應(yīng)的序號 const DWORD dwIndex = CLock::Create(); //進入臨界區(qū) CLock lock(dwIndex); //刪除相應(yīng)的臨界區(qū) CLock::Delete(dwIndex);

總結(jié)

以上是生活随笔為你收集整理的如何写优雅的代码(5)——远离临界区噩梦的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。