互斥量Mutex的簡單應用
一、互斥量的簡單介紹
互斥量是一個核心物件,它用來確保一個執行緒獨佔一個資源的訪問。互斥量與關鍵段的行為非常相似,並且互斥量可以用於不同程序中的執行緒互斥訪問資源。
使用互斥量Mutex主要將用到四個函式。下面是這些函式的原型和使用說明。
1) CreateMutex
函式功能:建立互斥量
函式原型:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner,
LPCTSTR lpName
);
函式說明:
第一個引數表示安全控制,一般直接傳入NULL。
第二個引數用來確定互斥量的初始擁有者。如果傳入TRUE表示互斥量物件內部會記錄建立它的執行緒的執行緒ID號並將遞迴計數設定為1,由於該執行緒ID非零,所以互斥量處於未觸發狀態。如果傳入FALSE,那麼互斥量物件內部的執行緒ID號將設定為NULL,遞迴計數設定為0,這意味互斥量不為任何執行緒佔用,處於觸發狀態。
第三個引數用來設定互斥量的名稱,在多個程序中的執行緒就是通過名稱來確保它們訪問的是同一個互斥量。
函式返回值:
成功返回一個表示互斥量的控制代碼,失敗返回NULL。
2)OpenMutex
函式功能:開啟互斥量,相當於使用互斥量
函式原型:
HANDLE OpenMutex(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName //名稱
);
函式說明:
第一個引數表示訪問許可權,對互斥量一般傳入MUTEX_ALL_ACCESS。詳細解釋可以檢視MSDN文件。
第二個引數表示互斥量控制代碼繼承性,一般傳入TRUE即可。
第三個引數表示名稱。某一個程序中的執行緒建立互斥量後,其它程序中的執行緒就可以通過這個函式來找到這個互斥量。
函式返回值:
成功返回一個表示互斥量的控制代碼,失敗返回NULL。
3)ReleaseMutex
函式功能:觸發互斥量,相當於解除對互斥量的佔用
函式原型:
BOOL ReleaseMutex(HANDLE hMutex);
函式返回值:
成功返回TRUE,失敗返回FALSE
4)CloseHandle
函式功能:清理互斥量,即釋放核心物件
函式原型:
BOOL CloseHandle(
HANDLE hObject
);
函式說明:
hObject:代表一個已開啟物件handle。
函式返回值:
成功返回TRUE,失敗返回FALSE,可以呼叫GetLastError()獲知失敗原因。
二、互斥量的示例使用
本文章將使用3個程序示例互斥量的使用,相當於互斥量阻止三個程序同時使用同一塊記憶體。但在貼程式碼之前先簡要說明一下WaitForSingleObject函式,該函式用於檢測hHandle事件的訊號狀態。
WaitForSingleObject
函式功能:用來檢測hHandle事件的訊號狀態,在某一執行緒中呼叫該函式時,執行緒暫時掛起,如果在掛起的dwMilliseconds毫秒內,執行緒所等待的物件變為有訊號狀態,則該函式立即返回;如果超時時間已經到達dwMilliseconds毫秒,但hHandle所指向的物件還沒有變成有訊號狀態,函式照樣返回。
函式原型:
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
函式說明:
hHandle:物件控制代碼。可以指定一系列的物件,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。
dwMilliseconds:定時時間間隔,單位為milliseconds(毫秒).如果指定一個非零值,函式處於等待狀態直到hHandle標記的物件被觸發,或者時間到了。如果dwMilliseconds為0,物件沒有被觸發訊號,函式不會進入一個等待狀態,它總是立即返回。如果dwMilliseconds為INFINITE,物件被觸發訊號後,函式才會返回。
函式返回值:
WAIT_ABANDONED 0x00000080:當hHandle為mutex時,如果擁有mutex的執行緒在結束時沒有釋放核心物件(通過呼叫ReleaseMutex函式釋放)會引發此返回值。
WAIT_OBJECT_0 0x00000000 :指定的物件出有有訊號狀態
WAIT_TIMEOUT 0x00000102:等待超時
WAIT_FAILED 0xFFFFFFFF :出現錯誤,可通過GetLastError得到錯誤程式碼
以上,就是WaitForSingleObject函式的簡要介紹。
接下來將介紹3個程序示例互斥量的使用:
程序1(建立互斥量):
#include <stdio.h>
#include <Windows.h>
const TCHAR MUTEX_NAME[] = L"Mutext_test";
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hMutex = CreateMutex(NULL, TRUE, MUTEX_NAME);
printf("互斥量已經建立,現在按任意鍵觸發互斥量\n");
getchar();
ReleaseMutex(hMutex);
printf("互斥量已經觸發\n");
CloseHandle(hMutex);
return 0;
}
程序2(開啟互斥量):
#include <stdio.h>
const TCHAR MUTEX_NAME[] = L"Mutext_test";
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, MUTEX_NAME);
if (hMutex == NULL)
{
printf("開啟互斥量失敗\n");
getchar();
return 0;
}
printf("等待中...\n");
DWORD dwResult = WaitForSingleObject(hMutex, 200 * 1000);
switch (dwResult)
{
case WAIT_ABANDONED:
printf("擁有互斥量的程序意外終止\n");
break;
case WAIT_OBJECT_0:
printf("已經收到訊號\n");
break;
case WAIT_TIMEOUT:
printf("訊號未在規定時間內送到\n");
break;
default:
break;
}
// PS:要在釋放互斥量之前加個getchar函式,這樣有助於觀察程序3在等待使用互斥量狀態
getchar();
ReleaseMutex(hMutex);
CloseHandle(hMutex);
return 0;
}
程序3(開啟互斥量):
const TCHAR MUTEX_NAME[] = L"Mutext_test";
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, MUTEX_NAME);
if (hMutex == NULL)
{
printf("開啟互斥量失敗\n");
getchar();
return -1;
}
printf("等待中...\n");
DWORD nResult = WaitForSingleObject(hMutex, 20 * 10000);
switch(nResult)
{
case WAIT_ABANDONED:
printf("建立互斥量程序已被廢棄\n");
break;
case WAIT_OBJECT_0:
printf("成功接收到訊號\n");
break;
case WAIT_TIMEOUT:
printf("等待時間已超時\n");
break;
default:
break;
}
getchar();
ReleaseMutex(hMutex);
CloseHandle(hMutex);
return 0;
}
執行結果如下:
當testOpenMutex1.exe 成功接收到訊號後按下任意鍵後就會解除對該互斥量的使用,從而使testOpenMutex.exe可以使用該互斥量。