| 導購 | 订阅 | 在线投稿
分享
 
 
當前位置: 王朝網路 >> c/c++ >> Win32下兩種用于C++的線程同步類(上)
 

Win32下兩種用于C++的線程同步類(上)

2008-06-01 02:10:18  編輯來源:互聯網  简体版  手機版  評論  字體: ||
 
 
  線程同步是多線程程序設計的核心內容,它的目的是正確處理多線程並發時的各種問題,例如線程的等待、多個線程訪問同一數據時的互斥,防死鎖等。Win32提供多種內核對象和手段用于線程同步,如互斥量、信號量、事件、臨界區等。所不同的是,互斥量、信號量、事件都是Windows的內核對象,當程序對這些對象進行控制時會自動轉換到核心態,而臨界區本身不是內核對象,它是工作在用戶態的。我們知道從用戶態轉換到核心態是需要以時間爲代價的,所以假如能在用戶態就簡單解決的問題,就可以不必勞煩核心態了。

  這裏我要說的是兩種用于C++的多線程同步類,通過對這兩種類的使用就可以方便的實現對變量或代碼段的加鎖控制,從而防止多線程對變量不正確的操作。

  所謂加鎖,就是說當我們要訪問某要害變量之前,都需要首先獲得答應才能繼續,假如未獲得答應則只有等待。一個要害變量擁有一把鎖,一個線程必須先得到這把鎖(其實稱爲鑰匙可能更形象)才可以訪問這個變量,而當某個變量持有這把鎖的時候,其他線程就不能重複的得到它,只有等持有鎖的線程把鎖歸還以後其他線程才有可能得到它。之所以這樣做,就是爲了防止一個線程讀取某對象途中另一線程對它進行了修改,或兩線程同時對一變量進行修改,例如:

  // 全局:

  strUCt MyStruct ... { int a, b; } ;

  MyStruct s;

  // 線程1:

  int a = s.a;

  int b = s.b;

  // 線程2:

  s.a ++ ;

  s.b -- ;

  假如實際的執行順序就是上述書寫的順序那到沒有什麽,但假如線程2的執行打斷了線程1,變爲如下順序:

  int a = s.a; //線程1

  s.a++; //線程2

  s.b++; //線程2

  int b = s.b; //線程1

  那麽這時線程1讀出來的a和b就會有問題了,因爲a是在修改前讀的,而b是在修改後讀的,這樣讀出來的是不完整的數據,會對程序帶來不可預料的後果。天知道兩個程的調度順序是什麽樣的。爲了防止這種情況的出現,需要對變量s加鎖,也就是當線程1得到鎖以後就可以放心的訪問s,這時假如線程2要修改s,只有等線程1訪問完成以後將鎖釋放才可以,從而保證了上述兩線程交叉訪問變量的情況不會出現。

  使用Win32提供的臨界區可以方便的實現這種鎖:

  // 全局:

  CRITICAL_SECTION cs;

  InitializeCriticalSection( & cs);

  // 線程1:

  EnterCriticalSection( & cs);

  int a = s.a;

  int b = s.b;

  LeaveCriticalSection( & cs);

  // 線程2:

  EnterCriticalSection( & cs);

  s.a ++ ;

  s.b -- ;

  LeaveCriticalSection( & cs);

  // 最後:

  DeleteCriticalSection( & cs);

  代碼中的臨界區變量(cs)就可以看作是變量s的鎖,當函數EnterCriticalSection返回時,當前線程就獲得了這把鎖,之後就是對變量的訪問了。訪問完成後,調用LeaveCriticalSection表示釋放這把鎖,答應其他線程繼續使用它。

  假如每當需要對一個變量進行加鎖時都需要做這些操作,顯得有些麻煩,而且變量cs與s只有邏輯上的鎖關系,在語法上沒有什麽聯系,這對于鎖的治理帶來了不小的麻煩。程序員總是最懶的,可以想出各種偷懶的辦法來解決問題,例如讓被鎖的變量與加鎖的變量形成物理上的聯系,使得鎖變量成爲被鎖變量不可分割的一部分,這聽起來是個好主意。

  首先想到的是把鎖封閉在一個類裏,讓類的構造函數和析構函數來治理對鎖的初始化和鎖毀動作,我們稱這個鎖爲「實例鎖」:

  class InstanceLockBase

  ... {

  CRITICAL_SECTION cs;

  protected :

  InstanceLockBase() ... { InitialCriticalSection( & cs); }

  ~ InstanceLockBase() ... { DeleteCriticalSection( & cs); }

  } ;

  假如熟悉C++,看到這裏一定知道後面我要幹什麽了,對了,就是繼續,因爲我把構造函數和析構函數都聲明爲保護的(protected),這樣唯一的作用就是在子類裏使用它。讓我們的被保護數據從這個類繼續,那麽它們不就不可分割了嗎:

  struct MyStruct: public InstanceLockBase

  ... { … } ;

  什麽?結構體還能從類繼續?當然,C++中結構體和類除了成員的默認訪問控制不同外沒有什麽不一樣,class能做的struct也能做。此外,也許你還會問,假如被鎖的是個簡單類型,不能繼續怎麽辦,那麽要麽用一個類對這個簡單類型進行封裝(記得Java裏有int和Integer嗎),要麽只好手工治理它們的聯系了。假如被鎖類已經有了基類呢?沒關系,C++是答應多繼續的,多一個基類也沒什麽。

  現在我們的數據裏面已經包含一把鎖了,之後就是要添加加鎖和解鎖的動作,把它們作爲InstanceLockBase類的成員函數再合適不過了:

  class InstanceLockBase

  ... {

  CRITICAL_SECTION cs;

  void Lock() ... { EnterCriticalSection( & cs); }

  void Unlock() ... { LeaveCriticalSection( & cs); }

  …

  } ;

  看到這裏可能會發現,我把Lock和Unlock函數都聲明爲私有了,那麽如何訪問這兩個函數呢?是的,我們總是需要有一個地方來調用這兩個函數以實現加鎖和解鎖的,而且它們總應該成對出現,但C++語法本身沒能限制我們必須成對的調用兩個函數,假如加完鎖忘了解,那後果是嚴重的。這裏有一個例外,就是C++對于構造函數和析構函數的調用是自動成對的,對了,那就把對Lock和Unlock的調用專門寫在一個類的構造函數和析構函數中:

  

  

  class InstanceLock

  ... {

  InstanceLockBase * _pObj;

  public :

  InstanceLock(InstanceLockBase * pObj)

  ... {

  _pObj = pObj; // 這裏會保存一份指向s的指針,用于解鎖

  if (NULL != _pObj)

  _pObj -> Lock(); // 這裏加鎖

  }

  ~ InstanceLock()

  ... {

  if (NULL != _pObj)

  _pObj -> Unlock(); // 這裏解鎖

  }

  } ;

  最後別忘了在類InstanceLockBase中把InstanceLock聲明爲友元,使得它能正確訪問Lock和Unlock這兩個私有函數:

  class InstanceLockBase

  ... {

  friend class InstanceLock;

  …

  } ;

  好了,有了上面的基礎,現在對變量s的加解鎖治理變成了對InstanceLock的實例的生命周期的治理了。假如我們有一個函數ModifyS中要對s進行修改,那麽只要在函數一開始就聲明一個InstaceLock的實例,這樣整個函數就自動對s加鎖,一旦進入這個函數,其他線程就都不能獲得s的鎖了:

  void ModifyS()

  ... {

  InstanceLock lock ( & s); // 這裏已經實現加鎖了

  // some operations on s

  } // 一旦離開lock對象的作用域,自動解鎖

  假如是要對某函數中一部分代碼加鎖,只要用一對大括號把它們括起來再聲明一個lock就可以了:

  …

  ... {

  InstanceLock lock ( & s);

  // do something …

  }

  …

  好了,就是這麽簡單。下面來看一個測試。

  首先預備一個輸出函數,對我們理解程序有幫助。它會在輸出我們想輸出的內容同時打出行號和時間:

  void Say( char * text)

  ... {

  static int count = 0 ;

  SYSTEMTIME st;

  ::GetLocalTime( & st);

  printf( " %03d [%02d:%02d:%02d.%03d]%s " , ++ count, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, text);

  }

  當然,原則上當多線程都調用這個函數時應該對其靜態局部變量count進行加鎖,這裏就省略了。

  我們聲明一個非常簡單的被鎖的類型,並生成一個實例:

  class MyClass: public InstanceLockBase

  ... {} ;

  MyClass mc;

  子線程的任務就是對這個對象加鎖,然後輸出一些信息:

  DWord CALLBACK ThreadProc(LPVOID param)

  ... {

  InstanceLock il( & mc);

  Say( " in sub thread, lock " );

  Sleep( 2000 );

  Say( " in sub thread, unlock " );

  return 0 ;

  }

  這裏會輸出兩條信息,一是在剛剛獲得鎖的時間,二是在釋放鎖的時候,中間通過Sleep來延遲2秒。

  主線程負責開啓子線程,然後也對mc加鎖:

  CreateThread( 0 , 0 , ThreadProc, 0 , 0 , 0 );

  ... {

  InstanceLock il( & mc);

  Say( " in main thread, lock " );

  Sleep( 3000 );

  Say( " in main thread, lock " );

  }

  運行此程序,得到的輸出如下:

  001 [13:43:23.781]in main thread, lock

  002 [13:43:26.781]in main thread, lock

  003 [13:43:26.781]in sub thread, lock

  004 [13:43:28.781]in sub thread, unlock

  從其輸出的行號和時間可以清楚的看到兩個線程間的互斥:當主線程恰好首先獲得鎖時,它會延遲3秒,然後釋放鎖,之後子線程才得以繼續進行。這個例子也證實我們的類工作的很好。

  總結一下,要使用InstanceLock系列類,要做的就是:

  1、讓被鎖類從InstanceLockBase繼續

  2、所有要訪問被鎖對象的代碼前面聲明InstanceLock的實例,並傳入被鎖對象的指針。

  附:完整源代碼:

  #pragma once

  #include < windows.h >

  class InstanceLock;

  class InstanceLockBase

  ... {

  friend class InstanceLock;

  CRITICAL_SECTION cs;

  void Lock()

  ... {

  ::EnterCriticalSection( & cs);

  }

  void Unlock()

  ... {

  ::LeaveCriticalSection( & cs);

  }

  protected :

  InstanceLockBase()

  ... {

  ::InitializeCriticalSection( & cs);

  }

  ~ InstanceLockBase()

  ... {

  ::DeleteCriticalSection( & cs);

  }

  } ;

  

   class InstanceLock

  ... {

  InstanceLockBase * _pObj;

  public :

  InstanceLock(InstanceLockBase * pObj)

  ... {

  _pObj = pObj;

  if (NULL != _pObj)

  _pObj -> Lock();

  }

  ~ InstanceLock()

  ... {

  if (NULL != _pObj)

  _pObj -> Unlock();

  }

  } ;
 
 
 
上一篇《使用Rational進行C++轉換的技巧》
下一篇《C++程序的異常處理技巧》
 
 
 
 
 
 
日版寵物情人插曲《Winding Road》歌詞

日版寵物情人2017的插曲,很帶節奏感,日語的,女生唱的。 最後聽見是在第8集的時候女主手割傷了,然後男主用嘴幫她吸了一下,插曲就出來了。 歌手:Def...

兄弟共妻,我成了他們夜裏的美食

老鍾家的兩個兒子很特別,就是跟其他的人不太一樣,魔一般的執著。兄弟倆都到了要結婚的年齡了,不管自家老爹怎麽磨破嘴皮子,兄弟倆說不娶就不娶,老父母爲兄弟兩操碎了心...

如何磨出破洞牛仔褲?牛仔褲怎麽剪破洞?

把牛仔褲磨出有線的破洞 1、具體工具就是磨腳石,下面墊一個硬物,然後用磨腳石一直磨一直磨,到把那塊磨薄了,用手撕開就好了。出來的洞啊很自然的。需要貓須的話調幾...

我就是掃描下圖得到了敬業福和愛國福

先來看下敬業福和愛國福 今年春節,支付寶再次推出了“五福紅包”活動,表示要“把欠大家的敬業福都還給大家”。 今天該活動正式啓動,和去年一樣,需要收集“五福”...

冰箱異味産生的原因和臭味去除的方法

有時候我們打開冰箱就會聞到一股異味,冰箱裏的這種異味是因爲一些物質發出的氣味的混合體,聞起來讓人惡心。 産生這些異味的主要原因有以下幾點。 1、很多人有這種習...

《極品家丁》1-31集大結局分集劇情介紹

簡介 《極品家丁》講述了現代白領林晚榮無意回到古代金陵,並追隨蕭二小姐化名“林三”進入蕭府,不料卻陰差陽錯上演了一出低級家丁拼搏上位的“林三升職記”。...

李溪芮《極品家丁》片尾曲《你就是我最愛的寶寶》歌詞

你就是我最愛的寶寶 - 李溪芮 (電視劇《極品家丁》片尾曲) 作詞:常馨內 作曲:常馨內 你的眉 又鬼馬的挑 你的嘴 又壞壞的笑 上一秒吵鬧 下...

烏梅的功效與作用以及烏梅的食用禁忌有哪些?

烏梅,又稱春梅,中醫認爲,烏梅味酸,性溫,無毒,具有安心、除熱、下氣、祛痰、止渴調中、殺蟲的功效,治肢體痛、肺痨病。烏梅泡水喝能治傷寒煩熱、止吐瀉,與幹姜一起制...

什麽是脂肪粒?如何消除臉部脂肪粒?

什麽是脂肪粒 在我們的臉上總會長一個個像脂肪的小顆粒,弄也弄不掉,而且顔色還是白白的。它既不是粉刺也不是其他的任何痘痘,它就是脂肪粒。 脂肪粒雖然也是由油脂...

網絡安全治理:國家安全保障的主要方向是打擊犯罪,而不是處置和懲罰受害者

來源:中國青年報 新的攻擊方法不斷湧現,黑客幾乎永遠占據網絡攻擊的上風,我們不可能通過技術手段杜絕網絡攻擊。國家安全保障的主要方向是打擊犯罪,而不是處置和懲罰...

河南夫妻在溫嶺網絡直播“造人”內容涉黃被刑事拘留

夫妻網絡直播“造人”爆紅   1月9日,溫嶺城北派出所接到南京警方的協查通告,他們近期打掉了一個涉黃直播APP平台。而根據掌握的線索,其中有一對涉案的夫妻主播...

如何防止牆紙老化?牆紙變舊變黃怎麽辦?

如何防止牆紙老化? (1)選擇透氣性好的牆紙 市場上牆紙的材質分無紡布的、木纖維的、PVC的、玻璃纖維基材的、布面的等,相對而言,PVC材質的牆紙最不透氣...

鮮肌之謎非日本生産VS鮮肌之謎假日貨是謠言

觀點一:破日本銷售量的“鮮肌之謎” 非日本生産 近一段時間,淘寶上架了一款名爲“鮮肌之謎的” 鲑魚卵巢美容液,號稱是最近日本的一款推出的全新護膚品,産品本身所...

中國最美古詩詞精選摘抄

系腰裙(北宋詞人 張先) 惜霜蟾照夜雲天,朦胧影、畫勾闌。人情縱似長情月,算一年年。又能得、幾番圓。 欲寄西江題葉字,流不到、五亭前。東池始有荷新綠,尚小如...

關于女人的經典語句

關于女人的經典語句1、【做一個獨立的女人】 思想獨立:有主見、有自己的人生觀、價值觀。有上進心,永遠不放棄自己的理想,做一份自己喜愛的事業,擁有快樂和成就...

未來我們可以和性愛機器人結婚嗎?

你想體驗機器人性愛嗎?你想和性愛機器人結婚嗎?如果你想,機器人有拒絕你的權利嗎? 近日,第二屆“國際人類-機器人性愛研討會”大會在倫敦金史密斯大學落下帷幕。而...

全球最變態的十個地方

10.土耳其地下洞穴城市 變態指數:★★☆☆☆ 這是土耳其卡帕多西亞的一個著名景點,傳說是當年基督教徒們爲了躲避戰爭而在此修建。裏面曾住著20000人,...

科學家稱,人類死亡後意識將在另外一個宇宙中繼續存活

據英國《每日快報》報道,一位科學家兼理論家Robert Lanza博士宣稱,世界上並不存在人類死亡,死亡的只是身體。他認爲我們的意識借助我們體內的能量生存,而且...

《屏裏狐》片頭曲《我愛狐狸精》歌詞是什麽?

《我愛狐狸精》 - 劉馨棋   (電視劇《屏裏狐》主題曲)   作詞:金十三&李旦   作曲:劉嘉   狐狸精 狐狸仙   千年修...

 
 
 
線程同步是多線程程序設計的核心內容,它的目的是正確處理多線程並發時的各種問題,例如線程的等待、多個線程訪問同一數據時的互斥,防死鎖等。Win32提供多種內核對象和手段用于線程同步,如互斥量、信號量、事件、臨界區等。所不同的是,互斥量、信號量、事件都是Windows的內核對象,當程序對這些對象進行控制時會自動轉換到核心態,而臨界區本身不是內核對象,它是工作在用戶態的。我們知道從用戶態轉換到核心態是需要以時間爲代價的,所以假如能在用戶態就簡單解決的問題,就可以不必勞煩核心態了。   這裏我要說的是兩種用于C++的多線程同步類,通過對這兩種類的使用就可以方便的實現對變量或代碼段的加鎖控制,從而防止多線程對變量不正確的操作。   所謂加鎖,就是說當我們要訪問某要害變量之前,都需要首先獲得答應才能繼續,假如未獲得答應則只有等待。一個要害變量擁有一把鎖,一個線程必須先得到這把鎖(其實稱爲鑰匙可能更形象)才可以訪問這個變量,而當某個變量持有這把鎖的時候,其他線程就不能重複的得到它,只有等持有鎖的線程把鎖歸還以後其他線程才有可能得到它。之所以這樣做,就是爲了防止一個線程讀取某對象途中另一線程對它進行了修改,或兩線程同時對一變量進行修改,例如: // 全局: strUCt MyStruct ... { int a, b; } ; MyStruct s; // 線程1: int a = s.a; int b = s.b; // 線程2: s.a ++ ; s.b -- ;   假如實際的執行順序就是上述書寫的順序那到沒有什麽,但假如線程2的執行打斷了線程1,變爲如下順序: int a = s.a; //線程1 s.a++; //線程2 s.b++; //線程2 int b = s.b; //線程1   那麽這時線程1讀出來的a和b就會有問題了,因爲a是在修改前讀的,而b是在修改後讀的,這樣讀出來的是不完整的數據,會對程序帶來不可預料的後果。天知道兩個程的調度順序是什麽樣的。爲了防止這種情況的出現,需要對變量s加鎖,也就是當線程1得到鎖以後就可以放心的訪問s,這時假如線程2要修改s,只有等線程1訪問完成以後將鎖釋放才可以,從而保證了上述兩線程交叉訪問變量的情況不會出現。   使用Win32提供的臨界區可以方便的實現這種鎖: // 全局: CRITICAL_SECTION cs; InitializeCriticalSection( & cs); // 線程1: EnterCriticalSection( & cs); int a = s.a; int b = s.b; LeaveCriticalSection( & cs); // 線程2: EnterCriticalSection( & cs); s.a ++ ; s.b -- ; LeaveCriticalSection( & cs); // 最後: DeleteCriticalSection( & cs);   代碼中的臨界區變量(cs)就可以看作是變量s的鎖,當函數EnterCriticalSection返回時,當前線程就獲得了這把鎖,之後就是對變量的訪問了。訪問完成後,調用LeaveCriticalSection表示釋放這把鎖,答應其他線程繼續使用它。   假如每當需要對一個變量進行加鎖時都需要做這些操作,顯得有些麻煩,而且變量cs與s只有邏輯上的鎖關系,在語法上沒有什麽聯系,這對于鎖的治理帶來了不小的麻煩。程序員總是最懶的,可以想出各種偷懶的辦法來解決問題,例如讓被鎖的變量與加鎖的變量形成物理上的聯系,使得鎖變量成爲被鎖變量不可分割的一部分,這聽起來是個好主意。   首先想到的是把鎖封閉在一個類裏,讓類的構造函數和析構函數來治理對鎖的初始化和鎖毀動作,我們稱這個鎖爲「實例鎖」: class InstanceLockBase ... { CRITICAL_SECTION cs; protected : InstanceLockBase() ... { InitialCriticalSection( & cs); } ~ InstanceLockBase() ... { DeleteCriticalSection( & cs); } } ;   假如熟悉C++,看到這裏一定知道後面我要幹什麽了,對了,就是繼續,因爲我把構造函數和析構函數都聲明爲保護的(protected),這樣唯一的作用就是在子類裏使用它。讓我們的被保護數據從這個類繼續,那麽它們不就不可分割了嗎: struct MyStruct: public InstanceLockBase ... { … } ;   什麽?結構體還能從類繼續?當然,C++中結構體和類除了成員的默認訪問控制不同外沒有什麽不一樣,class能做的struct也能做。此外,也許你還會問,假如被鎖的是個簡單類型,不能繼續怎麽辦,那麽要麽用一個類對這個簡單類型進行封裝(記得Java裏有int和Integer嗎),要麽只好手工治理它們的聯系了。假如被鎖類已經有了基類呢?沒關系,C++是答應多繼續的,多一個基類也沒什麽。   現在我們的數據裏面已經包含一把鎖了,之後就是要添加加鎖和解鎖的動作,把它們作爲InstanceLockBase類的成員函數再合適不過了: class InstanceLockBase ... {  CRITICAL_SECTION cs;  void Lock() ... { EnterCriticalSection( & cs); }  void Unlock() ... { LeaveCriticalSection( & cs); }  … } ;   看到這裏可能會發現,我把Lock和Unlock函數都聲明爲私有了,那麽如何訪問這兩個函數呢?是的,我們總是需要有一個地方來調用這兩個函數以實現加鎖和解鎖的,而且它們總應該成對出現,但C++語法本身沒能限制我們必須成對的調用兩個函數,假如加完鎖忘了解,那後果是嚴重的。這裏有一個例外,就是C++對于構造函數和析構函數的調用是自動成對的,對了,那就把對Lock和Unlock的調用專門寫在一個類的構造函數和析構函數中: class InstanceLock ... {  InstanceLockBase * _pObj;  public :   InstanceLock(InstanceLockBase * pObj)   ... {    _pObj = pObj; // 這裏會保存一份指向s的指針,用于解鎖    if (NULL != _pObj)    _pObj -> Lock(); // 這裏加鎖   }   ~ InstanceLock()   ... {    if (NULL != _pObj)    _pObj -> Unlock(); // 這裏解鎖  } } ;   最後別忘了在類InstanceLockBase中把InstanceLock聲明爲友元,使得它能正確訪問Lock和Unlock這兩個私有函數: class InstanceLockBase ... {  friend class InstanceLock;  … } ;   好了,有了上面的基礎,現在對變量s的加解鎖治理變成了對InstanceLock的實例的生命周期的治理了。假如我們有一個函數ModifyS中要對s進行修改,那麽只要在函數一開始就聲明一個InstaceLock的實例,這樣整個函數就自動對s加鎖,一旦進入這個函數,其他線程就都不能獲得s的鎖了: void ModifyS() ... {  InstanceLock lock ( & s); // 這裏已經實現加鎖了  // some operations on s } // 一旦離開lock對象的作用域,自動解鎖   假如是要對某函數中一部分代碼加鎖,只要用一對大括號把它們括起來再聲明一個lock就可以了: … ... {  InstanceLock lock ( & s);  // do something … } …   好了,就是這麽簡單。下面來看一個測試。   首先預備一個輸出函數,對我們理解程序有幫助。它會在輸出我們想輸出的內容同時打出行號和時間: void Say( char * text) ... {  static int count = 0 ;  SYSTEMTIME st;  ::GetLocalTime( & st);  printf( " %03d [%02d:%02d:%02d.%03d]%s " , ++ count, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, text); }   當然,原則上當多線程都調用這個函數時應該對其靜態局部變量count進行加鎖,這裏就省略了。   我們聲明一個非常簡單的被鎖的類型,並生成一個實例: class MyClass: public InstanceLockBase ... {} ; MyClass mc;   子線程的任務就是對這個對象加鎖,然後輸出一些信息: DWord CALLBACK ThreadProc(LPVOID param) ... {  InstanceLock il( & mc);  Say( " in sub thread, lock " );  Sleep( 2000 );  Say( " in sub thread, unlock " );  return 0 ; }   這裏會輸出兩條信息,一是在剛剛獲得鎖的時間,二是在釋放鎖的時候,中間通過Sleep來延遲2秒。   主線程負責開啓子線程,然後也對mc加鎖: CreateThread( 0 , 0 , ThreadProc, 0 , 0 , 0 ); ... {  InstanceLock il( & mc);  Say( " in main thread, lock " );  Sleep( 3000 );  Say( " in main thread, lock " ); }   運行此程序,得到的輸出如下: 001 [13:43:23.781]in main thread, lock 002 [13:43:26.781]in main thread, lock 003 [13:43:26.781]in sub thread, lock 004 [13:43:28.781]in sub thread, unlock   從其輸出的行號和時間可以清楚的看到兩個線程間的互斥:當主線程恰好首先獲得鎖時,它會延遲3秒,然後釋放鎖,之後子線程才得以繼續進行。這個例子也證實我們的類工作的很好。   總結一下,要使用InstanceLock系列類,要做的就是:   1、讓被鎖類從InstanceLockBase繼續   2、所有要訪問被鎖對象的代碼前面聲明InstanceLock的實例,並傳入被鎖對象的指針。   附:完整源代碼: #pragma once #include < windows.h > class InstanceLock; class InstanceLockBase ... {  friend class InstanceLock;  CRITICAL_SECTION cs;  void Lock()  ... {   ::EnterCriticalSection( & cs);  }  void Unlock()  ... {   ::LeaveCriticalSection( & cs);  }  protected :  InstanceLockBase()  ... {   ::InitializeCriticalSection( & cs);  }  ~ InstanceLockBase()  ... {   ::DeleteCriticalSection( & cs);  } } ; class InstanceLock ... {  InstanceLockBase * _pObj;  public :   InstanceLock(InstanceLockBase * pObj)   ... {    _pObj = pObj;    if (NULL != _pObj)     _pObj -> Lock();   }  ~ InstanceLock()  ... {   if (NULL != _pObj)    _pObj -> Unlock();  } } ;
󰈣󰈤
 
 
 
  免責聲明:本文僅代表作者個人觀點,與王朝網路無關。王朝網路登載此文出於傳遞更多信息之目的,並不意味著贊同其觀點或證實其描述,其原創性以及文中陳述文字和內容未經本站證實,對本文以及其中全部或者部分內容、文字的真實性、完整性、及時性本站不作任何保證或承諾,請讀者僅作參考,並請自行核實相關內容。
 
 
小龍女彤彤之情溢皇都
龔潔
智能手機形象美女
崔潔彤
回家的路上----
中國一站(哈爾濱)
清明植物園的花。
桃花堤印象之豎版
 
>>返回首頁<<
 
 熱帖排行
 
 
 
 
© 2005- 王朝網路 版權所有