基于多进程并发-进程同步之互斥锁(Mutex)

一、Windows的互斥锁Mutex是什么?

1、为Windows内核对象
2、实现进程线程的互斥/同步
3、实现为Windows的一组API

二、Windows的互斥锁各接口

1、CreateMutex函数
作用:创建互斥对象,并获取互斥对象的void句柄;或者获取互斥对象的void句柄。
a、原型:

HANDLE CreateMutex(  
        LPSECURITY_ATTRIBUTES   lpMutexAttributes,        
        BOOL                	bInitialOwner,         
        LPCTSTR         		lpName           
);  

b、接口说明:
lpMutexAttributes:指向SECURITY_ATTRIBUTES结构的指针

  • 如果此参数为 NULL,则子进程无法继承句柄。结构的 lpSecurityDescriptor 成员为新的互斥指定安全描述符。 如果lpMutexAttributes为NULL,则mutex获取默认的安全描述符。

bInitialOwner:创建互斥对象的进程\线程A是否占有权

  • TRUE:占有,FALSE:不占有;
  • 一般为FALSE,不为任何进程\线程所占用;
  • 若为TRUE,表希望A占有该互斥对象,若真正创建了该互斥对象,则无论A是否拿到锁,它进程\线程B中的wait函数将阻塞,直到A调用CloseHandle或消亡后,B中的wait函数才会返回WAIT_ABANDONED(128L)。

lpName:指向互斥对象名的字符串指针

  • 名称区分大小写;
  • 如果为 NULL,则会在没有名称的情况下创建互斥对象,将无法实现进程间同步;
  • 可添加全局”或“本地”前缀,如"Local\name"和"Global\name",以便应用程序能够支持多个用户。

返回值:指向互斥对象的void*句柄

  • 如执行成功,返回互斥体对象的句柄,NULL表示出错;
  • 一般情况,无论指定的名字互斥对象是否已经存在,都能成功拿到有效的void*句柄;
  • 若指定的名字互斥对象是否已经存在,则不会初始化新的互斥对象,GetLastError返回ERROR_ALREADY_EXISTS(183L),等同于调用OpenMutex函数。

2、OpenMutex
作用:获取互斥对象的void*句柄。
a、原型:

HANDLE OpenMutex(  
        DWORD					dwDesiredAccess,        
        BOOL                	bInheritHandle,         
        LPCTSTR         		lpName
);  

b、接口说明:
dwDesiredAccess:对互斥对象访问期望权限

  • 请指定MUTEX_ALL_ACCESS。

bInheritHandle:子进程能够继承句柄

  • 若为TRUE,则由此进程创建的进程将继承句柄;
  • 若为FALSE,子进程不会继承此句柄。

lpName:指向互斥对象名的字符串指针

  • 与CreateMutex同

返回值:指向互斥对象的void*句柄

  • 如果函数成功,则返回值是互斥对象的void*句柄;
  • 如果函数失败,则返回值为 NULL;如果命名互斥体不存在,该函数将失败,GetLastError返回ERROR_FILE_NOT_FOUND(2L)。

3、WaitForSingleObject
作用:获取互斥锁
a、原型:

DWORD WaitForSingleObject(
		HANDLE					hHandle, 
		DWORD					dwMilliseconds
);

b、接口说明:
hHandle:指向互斥对象的void*句柄

  • CreateMutex或OpenMutex函数的返回值。

dwMilliseconds:超时间隔(以毫秒为单位)

  • 如果指定了非零值,该函数将等待对象发出信号或间隔;
  • 如果dwMilliseconds为零,则如果对象未发出信号,则函数不会输入等待状态;它始终会立即返回;
  • 如果dwMilliseconds为INFINITE,则仅当发出对象信号时,该函数才会返回。

返回值:指示导致函数返回的事件

  • WAIT_OBJECT_0(0L),成功获取互斥锁;
  • WAIT_TIMEOUT(258L),等待超时;
  • WAIT_FAILED(0xFFFFFFFF),函数失败。 要获得更多的错误信息,请调用 GetLastError;
  • WAIT_ABANDONED(128L),见上文“1、CreateMutex --> b、接口说明:–> bInitialOwner的第三条”。

4、ReleaseMutex
作用:解锁
a、原型:

BOOL ReleaseMutex(
		HANDLE					hHandle, 
);

b、接口说明:
hHandle:指向互斥对象的void*句柄

  • CreateMutex或OpenMutex函数的返回值。
    返回值:解锁是否成功
    调用成功返回TRUE,此时另一个在等待该mutex的进程\线程,将得到信号停止等待(wait函数)。

例如:
WaitForSingleObject(hMutex,INFINITE); hMutex对象如果变为激发状态,这个函数就会返回,继续往下执行。

5、CloseHandle
作用:释放内核对象副本

BOOL CloseHandle(
		HANDLE					hObject, 
);

b、接口说明:
hHandle:指向互斥对象的void*句柄

  • CreateMutex或OpenMutex函数的返回值。
    返回值:解锁是否成功
    关闭一个句柄,并将这个句柄的引用计数减一,如果句柄的引用计数减到0,那么操作系统将释放这个核心对象的句柄。用CloseHandle来释放Mutex时,只是释放当前进程获得的句柄,而不会删除该Mutex内核对象。

三、Windows的进程互斥锁使用说明

1、不可跨PC
2、当多个进程对计算机上的同一份文件进行操作时候,需要对文件进行保护,防止多个进程同时对文件进行修改造成错误,因此可采用Windows的互斥锁Mutex来进行加锁。

// CreatMutex.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <stdio.h>
#include <windows.h>
#include <iostream>
using namespace std;

int main()
{
    
    
	//打开进程锁
	HANDLE hmutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, TEXT("MutexTest"));

	//创建进程锁
	if (hmutex == NULL)
	{
    
    
		cout<<"Create MutexTest!"<<endl;
		hmutex = CreateMutex(NULL, false, TEXT("MutexTest"));
	}

	//获取进程锁
	DWORD ts = WaitForSingleObject(hmutex, INFINITE);
	if (WAIT_OBJECT_0 == ts)
	{
    
    
		// 进行数据操作,下面是简单举例
		for (int i=0; i<10; i++)
		{
    
    
			cout << i <<endl;
			Sleep(1000);
		}
	}

	// 操作完成后释放进程锁
	ReleaseMutex(hmutex);

	if (hmutex != NULL)
	{
    
    
		CloseHandle(hmutex);
	}

	return 0;
}

四、需要注意的问题

如果一个进程A(线程A):HANDLE hMutexA=CreateMutex(NULL,true,“MyAppMutex”);创建了一个互斥体;
同时另一个进程B(线程B)也:HANDLE hMutexB=CreateMutex(NULL,true,“MyAppMutex”);这个时候hMutexB会得到已经存在的互斥体的句柄吗?
答:不会,而是接口成功会返回该互斥锁的句柄。但是可以通过GetLastError返回ERROR_ALREADY_EXISTS(183L)。

如有错误或不足欢迎评论指出!创作不易,转载请注明出处。如有帮助,记得点赞关注哦(⊙o⊙)
更多内容请关注个人博客:https://blog.csdn.net/qq_43148810

猜你喜欢

转载自blog.csdn.net/qq_43148810/article/details/130648613