前面文章介绍了使用mutex和semaphore在多线程场景中实现线程互斥。事实上,因为mutex, semaphore是内核对象,虽然是在某一个进程中创建的,但是由于进程间可以共享内核模块,故而使用mutex, semaphore在进程间作为互斥标识量也是可以的。
0. 使用mutex实现多进程间互斥
race_process_mutex_1.cpp
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
char name[50] = "multiple_process_shared_mutex_test";
void main()
{
HANDLE g_Mutex = CreateMutexA(NULL, TRUE, name); //如何句柄创建成功,则返回有效的句柄值
if(g_Mutex)
printf("句柄创建成功\n");
else
{
printf("句柄创建失败\n");
return;
}
char ch = getchar();
ReleaseMutex(g_Mutex);//离开互斥区
printf("宿主进程已经释放了互斥量,其余进程可以触发互斥量\n");
CloseHandle(g_Mutex);
}
race_process_mutex_2.cpp
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
char name[50] = "multiple_process_shared_mutex_test";
void main()
{
HANDLE mutex = OpenMutexA(MUTEX_ALL_ACCESS,TRUE,name);//MUTEX_ALL_ACCESS查找全部
if (mutex==NULL)
{
printf("给定参数名称的mutex内核对象打开失败,可能尚未创建该mutex\n");
system("pause");
return;
}
printf("----已搜索到指定的mutex内核对象,正在等待获取使用该对象-----\n");
DWORD res = WaitForSingleObject(mutex, 20000);
switch (res)
{
case WAIT_OBJECT_0:
printf("----收到信号,成功获取到该mutex,下面本进程可以进入critical section进行操作-----\n");
break;
case WAIT_TIMEOUT:
printf("----超时,mutex宿主进程依旧在声明使用该mutex中-----\n");
break;
case WAIT_ABANDONED:
printf("----mutex宿主进程意外终止-------\n");
break;
default:
break;
}
CloseHandle(mutex);
system("pause");
}
1. 使用semaphore实现多进程间互斥
race_process_semaphore_1.cpp
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
char name[50] = "multiple_process_shared_mutex_test";
void main()
{
HANDLE hsem = CreateSemaphoreA(NULL, 0, 1, name);
//第二各参数为0,代表进程创建信号量之时便声明了对该信号量的占用
printf("宿主进程创建信号量成功");
char ch = getchar();
ReleaseSemaphore(hsem, 1, NULL);
printf("宿主进程已释放对信号量的使用,其余进程可触发信号量");
CloseHandle(hsem);
}
race_process_semaphore_2.cpp
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
char name[50] = "multiple_process_shared_mutex_test";
void main()
{
HANDLE hsem = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, TRUE, name);
if (hsem == NULL)
{
printf("给定参数名称的semaphore内核对象打开失败,可能尚未创建该semaphore\n");
system("pause");
return;
}
printf("----已搜索到指定的semaphore内核对象,正在等待获取使用该对象-----\n");
DWORD res = WaitForSingleObject(hsem, 20000); //第二个参数20000,单位ms,代表最多监听该信号量20s
switch (res)
{
case WAIT_OBJECT_0:
printf("----收到信号,成功获取到该semaphore,下面本进程可以进入critical section进行操作-----\n");
break;
case WAIT_TIMEOUT:
printf("----超时,semaphore宿主进程依旧在声明使用该semaphore中-----\n");
break;
/*semaphore和event类似,并不能检测到宿主进程的主动中断,故而只能等待时间耗光后才会响应,故而这也是semaphore相比于Mutex的缺点。即semaphore的宿主进程主动终止了,该监听进程也只能被动地耗光所有的等待时间,而不能监听到对方进程终止了。
case WAIT_ABANDONED:
printf("----semaphore宿主进程意外终止-------");
break;
*/
default:
break;
}
CloseHandle(hsem);
system("pause");
}
2. 使用event实现多进程间协同执行
race_process_event_1.cpp
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
char name[50] = "multiple_process_shared_mutex_test";
void main()
{
HANDLE event = CreateEventA(NULL, FALSE, FALSE, name);
printf("宿主进程创建信号量成功");
char ch = getchar();
SetEvent(event);
printf("宿主进程激活了event,等待其他进程触发event");
CloseHandle(event);
system("pause");
}
race_process_event_2.cpp
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
char name[50] = "multiple_process_shared_mutex_test";
void main()
{
HANDLE event = OpenEventA(EVENT_ALL_ACCESS, TRUE, name);//打开事件
if (event == NULL)
{
printf("给定参数名称的event内核对象打开失败,可能尚未创建该event\n");
system("pause");
return;
}
printf("----已搜索到指定的event内核对象,正在等待获取使用该对象-----\n");
DWORD res = WaitForSingleObject(event, 20000);
switch (res)
{
case WAIT_OBJECT_0:
printf("----收到信号,成功激活目标event,下面本进程可以进行后续的协同操作-----\n");
break;
case WAIT_TIMEOUT:
printf("----超时,目标event的宿主进程依旧未激活该event该其他进程使用----\n");
break;
/*
//event机制其实是感知不到宿主进程中断丢失的情况,这也是event相比于Mutex最大的缺点
case WAIT_ABANDONED:
printf("-------目标event的宿主进程意外终止-------");
break;
*/
default:
break;
}
CloseHandle(event);
system("pause");
}
根据上面可以看到基本上内核对象都是可以改装使用在多进程间用于信息交换的,这是多进程间进行信号(开或关)的交互方式,而多进程间更大规模的数据交互则涉及到其他的机制,如进程间Message(Windows socket套接字便属于这类),共享内存块、管道pipeline等技术。
总结本文的内容,简单的一句话,如果单纯只是开关锁,在两个进程中实现互斥,mutex比event和semaphre更安全,响应性更好。