線程同步 互斥量 Mutex 內核對象 CreateMutex

0、思考

1、相關api

CreateMutex
CreateMutexEx
OpenMutex
ReleaseMutex
CloseHandle
WaitForSingleObject
WaitForMultipleObjects

2、寫在前面

互斥量:確保一個線程獨佔對一個資源的訪問。(與關鍵代碼段行爲完全相同,只是互斥量屬於內核對象,關鍵代碼段屬於用戶模式下的同步對象)
互斥量包含一個使用計數、線程id以及一個遞歸計數。(後面有用)
異常:假設線程試圖等待一個未觸發的互斥量對象。在這種情況下,線程通常會進入等待狀態。但是,系統要檢查想要獲取互斥對象的線程ID是否與互斥
    對象內部記錄的線程ID相同。如果兩個線程ID相同,即使互斥對象處於未通知狀態,系統也允許該線程保持可調度狀態。

3、api說明

// 
// lpMutexAttributes:安全屬性。(通常爲NULL)
// bInitialOwner:互斥量初始狀態;觸發狀態(false),互斥量對象的線程id和遞歸計數都是0,不被任何線程佔用;未觸發狀態(true),對象線程
    id將被設爲調用線程的線程id,遞歸計數將被設爲1。(通常爲false)
// lpName:內核對象名稱
WINBASEAPI
__out_opt
HANDLE
WINAPI
CreateMutexA(
    __in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,
    __in     BOOL bInitialOwner,
    __in_opt LPCSTR lpName
);
WINBASEAPI
__out_opt
HANDLE
WINAPI
CreateMutexW(
    __in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,
    __in     BOOL bInitialOwner,
    __in_opt LPCWSTR lpName
);
#ifdef UNICODE
#define CreateMutex  CreateMutexW
#else
#define CreateMutex  CreateMutexA
#endif // !UNICODE

// dwFlags:0表示bInitialOwner的false,CREATE_MUTEX_INITIAL_OWNER表示true
// dwDesiredAccess:訪問權限
WINBASEAPI
__out_opt
HANDLE
WINAPI
CreateMutexExA(
    __in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,
    __in_opt LPCSTR lpName,
    __in     DWORD dwFlags,
    __in     DWORD dwDesiredAccess
);
WINBASEAPI
__out_opt
HANDLE
WINAPI
CreateMutexExW(
    __in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,
    __in_opt LPCWSTR lpName,
    __in     DWORD dwFlags,
    __in     DWORD dwDesiredAccess
);
#ifdef UNICODE
#define CreateMutexEx  CreateMutexExW
#else
#define CreateMutexEx  CreateMutexExA
#endif // !UNICODE

// 釋放互斥量。
// hMutex:內核對象句柄
WINBASEAPI
BOOL
WINAPI
ReleaseMutex(
    __in HANDLE hMutex
);

// 訪問互斥量對象。(當訪問權線程不再需要訪問資源時,必須調用)
// dwDesiredAccess:訪問權限。(通常爲SEMAPHORE_ALL_ACCESS)
// bInheritHandle:繼承性。(通常爲false)
// lpName:內核對象名稱。
WINBASEAPI
__out_opt
HANDLE
WINAPI
OpenMutexA(
    __in DWORD dwDesiredAccess,
    __in BOOL bInheritHandle,
    __in LPCSTR lpName
);
WINBASEAPI
__out_opt
HANDLE
WINAPI
OpenMutexW(
    __in DWORD dwDesiredAccess,
    __in BOOL bInheritHandle,
    __in LPCWSTR lpName
);
#ifdef UNICODE
#define OpenMutex  OpenMutexW
#else
#define OpenMutex  OpenMutexA
#endif // !UNICODE

4、C++封裝

#pragma once

#include <windows.h>


class ncMutex
{
public:
    ncMutex(LPCTSTR lpName = NULL)
    {
        _mutex = CreateMutex(NULL, False, lpName);
    }

    ~ncMutex()
    {
        CloseHandle(_mutex);
    }

public:
    DWORD lock (DWORD timeout = INFINITE)
    {
        return WaitForSingleObject (_mutex, timeout);
    }

    BOOL unlock ()
    {
        return ReleaseMutex(_mutex);
    }

private:
    HANDLE _mutex;
};

5、順藤摸瓜

線程所有權:除了互斥量,沒有任何一個會記住自己是哪個線程等待成功的內核對象。(這使得在未觸發狀態下,也能爲線程所獲得)
遺棄:如果佔用互斥量線程在釋放互斥量之前終止(使用ExitThread、TerminateThread、ExitProcess、TerminateProcess),由於佔用互斥量的線程
    已經終止,因此無法釋放它。
因爲系統會記錄所有的互斥量和線程內核對象,因此它確切知道互斥量何時被遺棄。當互斥量被遺棄時,系統會自動將互斥量對象的線程id和計數設爲0,
    然後檢查有沒有其他線程等待該互斥量。如果有,那麼系統會公平的選中一個正在等待的線程,把對象內部線程id設爲所選線程id,計數設爲1,這樣
    被選擇線程變成可調度狀態,只是等待函數在此種情況返回WAIT_ABANDONED(只適用於互斥量)。

鳴謝

覺的我寫的幫幫噠, 發個紅包賞賞賞

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章