1. 程式人生 > >【執行緒同步】臨界區與互斥量

【執行緒同步】臨界區與互斥量

Win32 中關於程序和執行緒的協調工作是由同步機制來完成的,同步機制相當於執行緒間的紅綠燈。

一. 同步和非同步

舉個例子:

PostMessage(),是把訊息放到對方的訊息佇列中,然後不管三七二十一,就回到原呼叫點繼續執行,這就是非同步。

SendMessage(),就像呼叫一般性函式,直到呼叫的函式結束,才會回到原點,這就是同步行為。

二. Critical Sections

如果一個執行緒已經進入某個臨界區,則另一個執行緒就絕不能夠進入同一個臨界區。

  

  //初始化一個臨界區
    VOID InitializeCriticalSection(
      LPCRITICAL_SECTION lpCriticalSection  // critical section
    );
     
    //消除一個臨界區
    VOID DeleteCriticalSection(
      LPCRITICAL_SECTION lpCriticalSection   // critical section
    );
     
    //進入臨界區
    VOID EnterCriticalSection(
      LPCRITICAL_SECTION lpCriticalSection  // critical section
    );
     
    //離開臨界區
    VOID LeaveCriticalSection(
      LPCRITICAL_SECTION lpCriticalSection   // critical section
    );
     
    例如:
    CRITICAL_SECTION gCriticalSection;
     
    void Function()
    {
        InitializeCriticalSection(&gCriticalSection);
     
        EnterCriticalSection(&gCriticalSection);
     
        //Do something here
     
        LeaveCriticalSection(&gCriticalSection);
     
        DeleteCriticalSection(&gCriticalSection);
    }

一旦執行緒進入一個臨界區,則它就可以一再的重複進入該臨界區,當然每個進入操作都必須對應離開操作。

也就是EnterCriticalSection( ),可以巢狀。

但是千萬不要在臨界區中呼叫 sleep(),或任何 Wait..() 函式。

臨界區的缺點是:沒有辦法知道進入臨界區中的那個執行緒是生是死。如果那個執行緒在進入臨界區後當掉了,而且沒有退出來,那麼系統就沒有辦法消除掉此臨界區。

三. Mutexes

Mutexes 用途和 Critical Section 非常類似,執行緒擁有 mutex 就好象執行緒進入 critical section 一樣,但是它犧牲速度以增加彈性。

一旦沒有任何執行緒擁有那個 mutex,這個 mutex 便處於激發狀態

它與臨界區的區別是:

1. Mutexes 操作要比 Critical Section 費時的多。

2. Mutexes 可以跨程序使用,Critical Section 則只能在同一程序中使用。

3. 等待一個 Mutex 時,你可以指定"結束等待"的時間長度,而 Critical Section 則不行。

    HANDLE CreateMutex(
      LPSECURITY_ATTRIBUTES lpMutexAttributes,  // 安全屬性,預設為NULL
      BOOL bInitialOwner,                       // initial owner
      LPCTSTR lpName                            // mutex 的名稱,是一個字串
    );
    //返回值:如果成功返回 handle,否則返回 NULL
     
    HANDLE OpenMutex(
      DWORD dwDesiredAccess,  // access
      BOOL bInheritHandle,    // inheritance option
      LPCTSTR lpName          // object name
    );
    //開啟一個已經存在的 mutex
     
    BOOL ReleaseMutex(
      HANDLE hMutex   // handle to mutex
    );
     
    //呼叫過程如下:
    CreateMutex(); //建立
    WaitForXXXObject(); //等待
     
    ReleaseMutex(); //釋放
    CloseHandle(); //關閉

說明:

1. Mutex 的擁有權:

Mutex 的擁有權並非屬於那個產生它的執行緒,而是那個最後對些 Mutex 進行 WaitXXX() 操作並且尚未進行 ReleaseMutex() 操作的執行緒。

2. Mutex 被捨棄:

如果執行緒在結束前沒有呼叫 ReleaseMutex(),比如執行緒呼叫了 EXitThread() 或者因為當掉而結束。這時的 mutex 不會被摧毀,而是被視為"未被擁有"以及"未被激發"的狀態,在下一個 WaitXXX() 中執行緒會被以WAIT_ABANDONED_0 (WAIT_ABANDONED_0_n + 1 )來通知。

3. 最初擁有者:

CreateMutex(),第二個引數 bInitialOwner,允許你指定現行執行緒是否立刻擁有產生出來的 mutex。

如果沒有指定立刻擁有的情況:

    HANDLE hMutex = CreateMutex(NULL, FALSE, "Sample Name");
     
    int result = WaitForSingleObject(hMutex, INFINITE);

可能發生,在 CreateMutex 完成之後,發生了 context switch,執行權切換到另一個執行緒,那麼其它程序就有可能在 mutex 的產生者呼叫 WaitForSingleObject( ) 之前,鎖住這個 mutex 物件。


原文:https://blog.csdn.net/lwbeyond/article/details/7617234