臨界區臨界資源CRITICAL_SECTION

Critical Section:
  不論是硬件臨界資源,還是軟件臨界資源,多個線程必須互斥地對它進行訪問。每個線程中訪問臨界資源的那段代碼稱爲臨界區(Critical Section)。
  每個線程中訪問臨界資源的那段程序稱爲臨界區(Critical Section)(臨界資源是一次僅允許一個線程使用的共享資源)。每次只准許一個線程進入臨界區,進入後不允許其他線程進入。不論是硬件臨界資源,還是軟件臨界資源,多個線程必須互斥地對它進行訪問。
  多個線程中涉及到同一個臨界資源的臨界區稱爲相關臨界區。
  線程進入臨界區的調度原則是: ①如果有若干線程要求進入空閒的臨界區,一次僅允許一個線程進入。②任何時候,處於臨界區內的線程不可多於一個。如已有線程進入自己的臨界區,則其它所有試圖進入臨界區的線程必須等待。③進入臨界區的線程要在有限時間內退出,以便其它線程能及時進入自己的臨界區。④如果線程不能進入自己的臨界區,則應讓出CPU,避免線程出現“忙等”現象。
  如果有多個線程試圖同時訪問臨界區,那麼在有一個線程進入後其他所有試圖訪問此臨界區的線程將被掛起,並一直持續到進入臨界區的線程離開。臨界區在被釋放後,其他線程可以繼續搶佔,並以此達到用原子方式操作共享資源的目的。
  臨界區在使用時以CRITICAL_SECTION結構對象保護共享資源,並分別用EnterCriticalSection()和LeaveCriticalSection()函數去標識和釋放一個臨界區。所用到的CRITICAL_SECTION結構對象必須經過InitializeCriticalSection()的初始化後才能使用,而且必須確保所有線程中的任何試圖訪問此共享資源的代碼都處在此臨界區的保護之下。否則臨界區將不會起到應有的作用,共享資源依然有被破壞的可能。
  下面通過一段代碼展示了臨界區在保護多線程訪問的共享資源中的作用。通過兩個線程來分別對全局變量g_cArray[10]進行寫入操作,用臨界區結構對象g_cs來保持線程的同步,並在開啓線程前對其進行初始化。爲了使實驗效果更加明顯,體現出臨界區的作用,在線程函數對共享資源g_cArray[10]的寫入時,以Sleep()函數延遲1毫秒,使其他線程同其搶佔CPU的可能性增大。如果不使用臨界區對其進行保護,則共享資源數據將被破壞(參見圖1(a)所示計算結果),而使用臨界區對線程保持同步後則可以得到正確的結果(參見圖1(b)所示計算結果)。代碼實現清單附下:
  // 臨界區結構對象
  CRITICAL_SECTION g_cs;
  // 共享資源
  char g_cArray[10];
  UINT ThreadProc10(LPVOID pParam)
  {
  // 進入臨界區
  EnterCriticalSection(&g_cs);
  // 對共享資源進行寫入操作
  for (int i = 0; i < 10; i++)
  {
  g_cArray = a;
  Sleep(1);
  }
  // 離開臨界區
  LeaveCriticalSection(&g_cs);
  return 0;
  }
  UINT ThreadProc11(LPVOID pParam)
  {
  // 進入臨界區
  EnterCriticalSection(&g_cs);
  // 對共享資源進行寫入操作
  for (int i = 0; i < 10; i++)
  {
  g_cArray[10 - i - 1] = b;
  Sleep(1);
  }
  // 離開臨界區
  LeaveCriticalSection(&g_cs);
  return 0;
  }
  ……
  void CSample08View::OnCriticalSection()
  {
  // 初始化臨界區
  InitializeCriticalSection(&g_cs);
  // 啓動線程
  AfxBeginThread(ThreadProc10, NULL);
  AfxBeginThread(ThreadProc11, NULL);
  // 等待計算完畢
  Sleep(300);
  // 報告計算結果
  CString sResult = CString(g_cArray);
  AfxMessageBox(sResult);
  }
  在使用臨界區時,一般不允許其運行時間過長,只要進入臨界區的線程還沒有離開,其他所有試圖進入此臨界區的線程都會被掛起而進入到等待狀態,並會在一定程度上影響程序的運行性能。尤其需要注意的是不要將等待用戶輸入或是其他一些外界干預的操作包含到臨界區。如果進入了臨界區卻一直沒有釋放,同樣也會引起其他線程的長時間等待。換句話說,在執行了EnterCriticalSection()語句進入臨界區後無論發生什麼,必須確保與之匹配的LeaveCriticalSection()都能夠被執行到。可以通過添加結構化異常處理代碼來確保LeaveCriticalSection()語句的執行。雖然臨界區同步速度很快,但卻只能用來同步本進程內的線程,而不可用來同步多個進程中的線程。
發佈了120 篇原創文章 · 獲贊 31 · 訪問量 48萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章