一、互斥量
互斥量是windows的一個內核對象,互斥量與關鍵段的作用相似,可以用來確保全局資源的互斥訪問。並且互斥量可以用在不同的進程中的線程互斥訪問全局資源。
二、相關函數說明
使用互斥量Mutex主要用到以下四個函數,下面將介紹這四個函數。
(一) 創建互斥量
1. 函數原型
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTE SlpMutexAttributes,
BOOL bInitialOwner,
LPCTSTR lpName
);
2.參數說明
-
第一個參數表示安全控制,一般直接傳入NULL。
-
第二個參數用來確定互斥量的初始擁有者。如果傳入TRUE表示互斥量對象內部會記錄創建它的線程的線程ID號並將遞歸計數設置為1,由於該線程ID非零,所以互斥量處於未觸發狀態。如果傳入FALSE,那么互斥量對象內部的線程ID號將設置為NULL,遞歸計數設置為0,這意味互斥量不為任何線程占用,處於觸發狀態。
-
第三個參數用來設置互斥量的名稱,在多個進程中的線程就是通過名稱來確保它們訪問的是同一個互斥量。
-
函數返回值:成功返回一個表示互斥量的句柄,失敗返回NULL。
(二) 打開互斥量
1. 函數原型
HANDLE OpenMutex(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);
2.參數說明
-
第一個參數表示
-
權限,對互斥量一般傳入MUTEX_ALL_ACCESS。
-
第二個參數表示互斥量句柄繼承性,一般傳入TRUE即可。
-
第三個參數表示名稱。某一個進程中的線程創建互斥量后,其它進程中的線程就可以通過這個函數來找到這個互斥量。
-
函數返回值:成功返回一個表示互斥量的句柄,失敗返回NULL。
(三) 觸發互斥量
1. 函數原型
BOOLReleaseMutex (HANDLEhMutex)
2.參數說明
傳入參數為從創建或打開互斥量時返回的句柄。 訪問互斥資源前應該要調用等待函數,結束訪問時就要調用ReleaseMutex()來表示自己已經結束訪問,其它線程可以開始訪問了。
(四) 釋放互斥量
由於互斥量是一個內核對象,釋放時直接調用 CloseHandle(HANDLE hObject) 函數就可以了,所有內核對象都是這樣釋放。
三、實例
1.創建並使用互斥量
#include <stdio.h>
#include <windows.h>
const unsigned int THREAD_NUM = 15;
unsigned int g_Count = 0;
HANDLE g_Mutex; //聲明一個內核對象
DWORD WINAPI ThreadFunc(LPVOID);
int main()
{
g_Mutex = CreateMutex(NULL,false,NULL); // 創建互斥量,初始化為觸發狀態
HANDLE hThread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++)
{
hThread[i] = CreateThread(NULL, 0, ThreadFunc, &i, 0, NULL); // 創建線程
}
WaitForMultipleObjects(THREAD_NUM, hThread, true, INFINITE); //一直等待,直到所有子線程全部返回
printf(" 總共 %d 個線程給 g_Count 的值加1,現在 g_Count = %d \n\n", THREAD_NUM, g_Count);
CloseHandle(g_Mutex); //釋放互斥量
return 0;
}
DWORD WINAPI ThreadFunc(LPVOID p)
{
int ThreadNum = *(int *)p;
WaitForSingleObject(g_Mutex, INFINITE); //等待互斥量觸發
printf(" 第 %d 個線程給全局資源 g_Count 的值加1,現在 g_Count = %d\n", ThreadNum, ++g_Count);
ReleaseMutex(g_Mutex); // 觸發互斥量
return 0;
}
程序運行結果如下圖:
上面的程序中使用互斥量實現了對全局資源的互斥訪問,但是並沒有按照我們所預料順序每個線程依次給 g_Count 加一。這說明使用互斥量只是實現了全局資源的互斥訪問,並沒有實現線程的同步,有關線程同步,會在接下來的文章中學習。
2.打開其他程序創建的互斥量
創建互斥量的程序(CreateMutex.c):
#include <stdio.h>
#include <windows.h>
const char MutexName[] = "MyMutex"; //互斥量名字
int main()
{
HANDLE hMutex = CreateMutex(NULL, TRUE, MutexName); //創建互斥量並初始化為未觸發狀態
printf("互斥量已經創建,按任意鍵觸發\n");
getch();
ReleaseMutex(hMutex); // 觸發互斥量
printf("互斥量已經被觸發\n");
CloseHandle(hMutex);
return 0;
}
使用互斥量的程序(OpenMutex.c):
#include <stdio.h>
#include <windows.h>
const char MutexName[] = "MyMutex"; //互斥量名字
int main()
{
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, MutexName); //打開互斥量
if (NULL != hMutex)
{
printf("打開互斥量成功,等待互斥量被觸發\n");
WaitForSingleObject(hMutex, INFINITE); // 等待互斥量被觸發
printf("互斥量已經被觸發\n");
}
else
{
printf("打開互斥量失敗。\n");
}
CloseHandle(hMutex);
return 0;
}
先運行第一個程序創建互斥量,輸出 互斥量已經創建,按任意鍵觸發
后,運行第二個程序,打開互斥量,打開互斥量后,在第一個程序窗口按任意鍵觸發互斥量,兩個窗口都會輸出互斥量已經被觸發。運行結果如下圖:
關於互斥量的使用就先介紹到這兒,其實前面的關鍵段介紹和互斥量都還有很多內容沒寫到,我打算單獨寫一篇來分析他們兩個的區別和共同點,這里就先不介紹了。