目录
1.CreateMutex函数原型
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全属性的指针
BOOL bInitialOwner, // 初始化互斥对象的所有者,如果希望进程立即拥有互斥体则设为FALSE
LPCTSTR lpName // 指向互斥对象名的指针
);
功能:创建一个互斥体(MUTEX)
- CreateMutex只是创建了一把锁, 这把锁你用来锁门还是锁抽屉还是锁你对象的内裤都由你自己决定。
- lpName是指定这把锁的名字. 你要不给这把锁取个名字都可以. 只是有了相同的名字, 在跨进程加锁的时候, 就可以得到同一把锁。
- HANDLE m_hMutex = CreateMutex(NULL,TRUE,“cplusplus_me”); 只是创建了一把锁, 到目前这句完成, 他没有锁任何东西。
如果函数成功执行,将返回一个互斥量对象的句柄。如果在CreateMutex()执行前已经存在有相同名字的互斥量,函数将返回这个已经存在互斥量的句柄,并且可以通过GetLastError()得到错误代码ERROR_ALREADY_EXIST
。可见,通过对错误代码ERROR_ALREADY_EXIST
的检测可以实现CreateMutex()对进程的互斥。
通过这个性质,就可以做一个避免进程重复打开的功能。
部分代码如下:
HANDLE m_hMutex = CreateMutex(NULL, FALSE, "Sample07");// 创建互斥量
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// 如果已有互斥量存在则释放句柄并复位互斥量
CloseHandle(m_hMutex);
m_hMutex = NULL;
// 程序退出
return FALSE;
};
2.WaitForSingleObject的理解
3.CreateMutex和WaitForSingleObject的配合使用
3.1如何加锁
一般使用WaitForSingleObject(hMutex, INFINITE);
加锁
3.2如何解锁
一般使用ReleaseMutex(hMutex);
解锁
这里写被加锁的东西. 一般是操作一些共享数据(占用系统内存)。
4.使用示例
问题:
假设 一个剧团卖票 一共10章票,3个电脑在卖它,每个人选座位买票大约花费500ms。模拟这样的场景,输出顺序是按购买顺序。
HANDLE hMutex = NULL;
//共享资源
static int num = 0; //目前一张都没卖出去
#define NUMSIZE 10 //num最大是10 可以更改
//子线程函数
unsigned long __stdcall ChildThreadFunc1(LPVOID pM)
{
while(num<NUMSIZE)
{
Sleep(500); //花500ms选取位置支付等过程
//加锁
WaitForSingleObject(hMutex, INFINITE);//等待互斥量
if(num<NUMSIZE)
{
num++;
printf("ThreadFunc1 num:%d\n", num);
}
//解锁
ReleaseMutex(hMutex); //执行完放弃对数据的所有权
}
return 0;
}
//子线程函数
unsigned long __stdcall ChildThreadFunc2(LPVOID pM)
{
while (num < NUMSIZE)
{
Sleep(500);
//加锁
WaitForSingleObject(hMutex, INFINITE);//等待互斥量
if (num<NUMSIZE)
{
num++;
printf(“ThreadFunc2 num:%d\n”, num);
}
//解锁
ReleaseMutex(hMutex); //执行完放弃对数据的所有权
}
return 0;
}
//子线程函数
unsigned long __stdcall ChildThreadFunc3(LPVOID pM)
{
while (num <NUMSIZE)
{
//加锁
Sleep(500);
WaitForSingleObject(hMutex, INFINITE);//等待互斥量
if (num<NUMSIZE)
{
num++;
printf(“ThreadFunc3 num:%d\n”, num);
}
//解锁
ReleaseMutex(hMutex); //执行完放弃对数据的所有权
}
return 0;
}
int main()
{
hMutex = CreateMutex(NULL,/*指向安全属性的指针*/
FALSE,/*初始化互斥对象的所有者 如果希望进程立即拥有互斥体则设为FALSE*/
NULL);/*指向互斥对象名的指针*/
HANDLE handle[3] = { 0 };
handle[0] = CreateThread(NULL, 0, ChildThreadFunc1, NULL, 0, NULL);
handle[1] = CreateThread(NULL, 0, ChildThreadFunc2, NULL, 0, NULL);
handle[2] = CreateThread(NULL, 0, ChildThreadFunc3, NULL, 0, NULL);
//阻塞等待
Sleep(8000);
printf("主线程 num:%d\n", num);
for (int i = 0; i < 3; i++)
{
CloseHandle(handle[i]);
}
CloseHandle(hMutex);
system("pause");
return 0;
}
运行结果:
5.注意
有如下代码:
运行结果是不是有点吃惊,其实你停下来仔细想想也就通了,每个进程本来就有一个主线程。因为你创建的mutex一开始没有拥有者,所以第一次WaitForSingleObject
会使当前线程获得mutex的所有权,并立即返回
mutex的所有线程再次等待mutex时也不会阻塞,因此第二次WaitForSingleObject
也会马上返回,因为你是在同一个线程中调用WaitForSingleObject的。