基于互斥量(Mutual Exclusion)的同步控制
实现进程互斥的核心思想比较简单:进程在启动时首先检查当前系统是否已经存在有此进程的实例,如果没有,进程将成功创建并设置标识实例已经存在的标记。此后再创建进程时将会通过该标记而知晓其实例已经存在,从而保证进程在系统中只能存在一个实例。
HANDLE WINAPI CreateMutex(
_In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,
_In_ BOOL bInitialOwner,
_In_opt_ LPCTSTR lpName
);
BOOL WINAPI CloseHandle(
_In_ HANDLE hObject
);
BOOL WINAPI ReleaseMutex(
_In_ HANDLE hMutex
);
通过CreateMutex函数完成互斥量的申请和设定,如果反回NULL则表明,该互斥量已经被占用,因此申请失败,不可以运行,其他值则表明注册成功。用CloseHandle关闭互斥量,关闭后的互斥量就可以重新被注册了。通过ReleaseMutex完成一个的锁定,可以使WaitForSingleOibject得以结束。
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
int num = 0;
CRITICAL_SECTION cs;
HANDLE hMutex = NULL;
unsigned WINAPI ThreadFun1(void *arg)
{
int cnt = *(int*)arg;
WaitForSingleObject(hMutex, INFINITE);
for (int i = 0; i < cnt; i++)
{
num += 1;
printf("Inc ");
Sleep(10);
}
ReleaseMutex(hMutex);
return 0;
}
unsigned WINAPI ThreadFun2(void *arg)
{
int cnt = *(int*)arg;
WaitForSingleObject(hMutex, INFINITE);
for (int i = 0; i < cnt; i++)
{
num -= 1;
printf("Dec ");
Sleep(10);
}
ReleaseMutex(hMutex);
return 0;
}
int main()
{
int param = 50;
HANDLE h[2];
unsigned int hd[2];
hMutex = CreateMutex(NULL, false, (LPCWSTR)"James");
h[0]= (HANDLE)_beginthreadex(NULL, 0, ThreadFun1, ¶m, 0, &hd[0]);
if (h[0] == 0)
{
printf("Can not create a thread 1.\n");
return 0;
}
h[1] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun2, ¶m, 0, &hd[1]);
if (h[1] == 0)
{
printf("Can not create a thread 2.\n");
return 0;
}
WaitForMultipleObjects(2, h, true, INFINITE);
CloseHandle(hMutex);
printf("The num is %d, and end of main.\n", num);
return 0;
}
其运行结果如下:
Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc
Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc
Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec
Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec
Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec
The num is 0, and end of main.
从运行结果上我们可以看出,在Inc运行阶段,系统是被阻塞的,没有dec算法可以执行。我们调整一下控制位置,将控制放置到循环体内部,这样我们就会得到一个交替运行的工作过程,其代码和运行结果如下:
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
int num = 0;
CRITICAL_SECTION cs;
HANDLE hMutex = NULL;
unsigned WINAPI ThreadFun1(void *arg)
{
int cnt = *(int*)arg;
for (int i = 0; i < cnt; i++)
{
WaitForSingleObject(hMutex, INFINITE);
num += 1;
printf("Inc ");
ReleaseMutex(hMutex);
Sleep(10);
}
return 0;
}
unsigned WINAPI ThreadFun2(void *arg)
{
int cnt = *(int*)arg;
for (int i = 0; i < cnt; i++)
{
WaitForSingleObject(hMutex, INFINITE);
num -= 1;
printf("Dec ");
ReleaseMutex(hMutex);
Sleep(10);
}
return 0;
}
int main()
{
int param = 50;
HANDLE h[2];
unsigned int hd[2];
hMutex = CreateMutex(NULL, false, (LPCWSTR)"James");
h[0]= (HANDLE)_beginthreadex(NULL, 0, ThreadFun1, ¶m, 0, &hd[0]);
if (h[0] == 0)
{
printf("Can not create a thread 1.\n");
return 0;
}
h[1] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun2, ¶m, 0, &hd[1]);
if (h[1] == 0)
{
printf("Can not create a thread 2.\n");
return 0;
}
WaitForMultipleObjects(2, h, true, INFINITE);
CloseHandle(hMutex);
printf("The num is %d, and end of main.\n", num);
return 0;
}
Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc
Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc
Dec Inc Inc Dec Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc
Dec Inc Inc Dec Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc
Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc
The num is 0, and end of main.