windows多线程(五) 互斥量 Mutex
一、互斥量
互斥量是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;
}
先运行第一个程序创建互斥量,输出 互斥量已经创建,按任意键触发
后,运行第二个程序,打开互斥量,打开互斥量后,在第一个程序窗口按任意键触发互斥量,两个窗口都会输出互斥量已经被触发。运行结果如下图:
关于互斥量的使用就先介绍到这儿,其实前面的关键段介绍和互斥量都还有很多内容没写到,我打算单独写一篇来分析他们两个的区别和共同点,这里就先不介绍了。