互斥量Mutex的简单应用

2022-09-13 14:54:12 浏览数 (2)

大家好,又见面了,我是你们的朋友全栈君。

一、互斥量的简单介绍

互斥量是一个内核对象,它用来确保一个线程独占一个资源的访问。互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源。

使用互斥量Mutex主要将用到四个函数。下面是这些函数的原型和使用说明。

1) CreateMutex

函数功能:创建互斥量

函数原型:

代码语言:javascript复制
HANDLE CreateMutex(
  LPSECURITY_ATTRIBUTES lpMutexAttributes,
  BOOL                  bInitialOwner,     
  LPCTSTR               lpName
);

函数说明:

第一个参数表示安全控制,一般直接传入NULL。

第二个参数用来确定互斥量的初始拥有者。如果传入TRUE表示互斥量对象内部会记录创建它的线程的线程ID号并将递归计数设置为1,由于该线程ID非零,所以互斥量处于未触发状态。如果传入FALSE,那么互斥量对象内部的线程ID号将设置为NULL,递归计数设置为0,这意味互斥量不为任何线程占用,处于触发状态。

第三个参数用来设置互斥量的名称,在多个进程中的线程就是通过名称来确保它们访问的是同一个互斥量。

函数返回值:

成功返回一个表示互斥量的句柄,失败返回NULL。

2)OpenMutex

函数功能:打开互斥量,相当于使用互斥量

函数原型:

代码语言:javascript复制
HANDLE OpenMutex(
 DWORD       dwDesiredAccess,
 BOOL        bInheritHandle,
 LPCTSTR     lpName     //名称
);

函数说明:

第一个参数表示访问权限,对互斥量一般传入MUTEX_ALL_ACCESS。详细解释可以查看MSDN文档。

第二个参数表示互斥量句柄继承性,一般传入TRUE即可。

第三个参数表示名称。某一个进程中的线程创建互斥量后,其它进程中的线程就可以通过这个函数来找到这个互斥量。

函数返回值:

成功返回一个表示互斥量的句柄,失败返回NULL。

3)ReleaseMutex

函数功能:触发互斥量,相当于解除对互斥量的占用

函数原型:

代码语言:javascript复制
BOOL ReleaseMutex(HANDLE hMutex);

函数返回值:

成功返回TRUE,失败返回FALSE

4)CloseHandle

函数功能:清理互斥量,即释放内核对象

函数原型:

代码语言:javascript复制
BOOL CloseHandle(
HANDLE hObject
);

函数说明:

hObject :代表一个已打开对象handle。

函数返回值:

成功返回TRUE,失败返回FALSE,可以调用GetLastError()获知失败原因。

二、互斥量的示例使用

本文章将使用3个进程示例互斥量的使用,相当于互斥量阻止三个进程同时使用同一块内存。但在贴代码之前先简要说明一下WaitForSingleObject函数,该函数用于检测hHandle事件的信号状态。

WaitForSingleObject

函数功能:用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。

函数原型:

代码语言:javascript复制
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);

函数说明:

hHandle:对象句柄。可以指定一系列的对象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。

dwMilliseconds:定时时间间隔,单位为milliseconds(毫秒).如果指定一个非零值,函数处于等待状态直到hHandle标记的对象被触发,或者时间到了。如果dwMilliseconds为0,对象没有被触发信号,函数不会进入一个等待状态,它总是立即返回。如果dwMilliseconds为INFINITE,对象被触发信号后,函数才会返回。

函数返回值:

WAIT_ABANDONED 0x00000080:当hHandle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象(通过调用ReleaseMutex函数释放)会引发此返回值。

WAIT_OBJECT_0 0x00000000 :指定的对象出有有信号状态

WAIT_TIMEOUT 0x00000102:等待超时

WAIT_FAILED 0xFFFFFFFF :出现错误,可通过GetLastError得到错误代码

以上,就是WaitForSingleObject函数的简要介绍。

接下来将介绍3个进程示例互斥量的使用:

进程1(创建互斥量):

代码语言:javascript复制
#include <stdio.h>
#include <Windows.h>
const TCHAR MUTEX_NAME[] = L"Mutext_test";

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hMutex = CreateMutex(NULL, TRUE, MUTEX_NAME);
	printf("互斥量已经创建,现在按任意键触发互斥量n");
	getchar();
	ReleaseMutex(hMutex);
	printf("互斥量已经触发n");
	CloseHandle(hMutex);
	return 0;
}

进程2(打开互斥量):

代码语言:javascript复制
#include <stdio.h>

const TCHAR MUTEX_NAME[] = L"Mutext_test";

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, MUTEX_NAME);
	if (hMutex == NULL)
	{
		printf("打开互斥量失败n");
		getchar();
		return 0;		
	}

	printf("等待中...n");
	DWORD dwResult = WaitForSingleObject(hMutex, 200 * 1000);
	switch (dwResult)
	{
	case WAIT_ABANDONED:
		printf("拥有互斥量的进程意外终止n");
		break;
	case WAIT_OBJECT_0:
		printf("已经收到信号n");
		break;
	case WAIT_TIMEOUT:
		printf("信号未在规定时间内送到n");
		break;
	default:
		break;
	}

    // PS:要在释放互斥量之前加个getchar函数,这样有助于观察进程3在等待使用互斥量状态
	getchar();
	ReleaseMutex(hMutex);
	CloseHandle(hMutex);
	return 0;
}

进程3(打开互斥量):

代码语言:javascript复制
const TCHAR MUTEX_NAME[] = L"Mutext_test";

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, MUTEX_NAME);
	if (hMutex == NULL)
	{
		printf("打开互斥量失败n");
		getchar();
		return -1;
	}

	printf("等待中...n");
	DWORD nResult = WaitForSingleObject(hMutex, 20 * 10000);
	switch(nResult)
	{
	case WAIT_ABANDONED:
		printf("创建互斥量进程已被废弃n");
		break;
	case WAIT_OBJECT_0:
		printf("成功接收到信号n");
		break;
	case WAIT_TIMEOUT:
		printf("等待时间已超时n");
		break;
	default:
		break;
	}
	getchar();
	ReleaseMutex(hMutex);
	CloseHandle(hMutex);
	return 0;
}

执行结果如下:

当testOpenMutex1.exe 成功接收到信号后按下任意键后就会解除对该互斥量的使用,从而使testOpenMutex.exe可以使用该互斥量。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/153199.html原文链接:https://javaforall.cn

0 人点赞