7.互斥体

本文探讨了互斥体(MUTANT)在多线程环境中的作用,特别是其如何解决等待对象被遗弃的问题,以及与事件(EVENT)和信号量(SEMAPHORE)的区别。互斥体不仅允许线程间的同步,还能实现跨进程同步,尤其在处理死锁和重入临界区时表现出优越性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么要有互斥体:等待对象被遗弃

互斥体(MUTANT)与事件(EVENT)和信号量(SEMAPHORE)一样,都可以用来·进行线程的同步控制。

但需要指出的是,这几个对象都是内核对象,这就意味着,通过这些对象可以进行跨进程的线程同步控制,比如:
在这里插入图片描述

A进程中的X线程与B进程中的Y线程,它们可以共同使用一个内核对象来进行线程同步控制。

极端情况:
如果B进程的Y线程还没有来得及调用修改SignalState的函数(如SetEvent)那么等待对象Z将被遗弃,这也就以为者x线程将永远等下去!

但如果我们用的是互斥体这种情况就很好解决,即使你的B进程的Y线程还没有来得及调用修改SignalState的函数,系统也会帮你修改。

因为创建了互斥体时,已经将互斥体已经将挂到了互斥体链表里,系统的函数可以通过binitialOwner查找到你当前线程所占用的互斥体。

当前线程并不维护事件与信号量,但是它维护互斥体对象

互斥体允许重入
在这里插入图片描述
上面调用了WaitForSingleObject等待对象是A,由于逻辑方面的要求后面有调用了WaitForMultipleObjects等待对象为A,B,C。

调用WaitForSingleObject(A)的时候已经将A对象的SignalState改为0了没有信号了,那就必须在你的WaitForSingleObject(A)执行完毕后调用SetEvent来修改SignalState为1。

这时就出问题了由于图上的A这时是没有信号的,这时你的代码将永远停留在WaitForMultipleObjects(A,B,C)这个位置,这种情况就叫死锁

解决方案:
如果你需要多次重复进入临界区的话,这时你的A对象是互斥体就不会出现死锁。

互斥体与事件/信号量的第二个区别就是它允许重复进入临界区。

MUTANT结构体介绍

kd> dt _KMUTANT
nt!_KMUTANT
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListEntry  : _LIST_ENTRY
   +0x018 OwnerThread      : Ptr32 _KTHREAD	//当前互斥体对象所属线程
   +0x01c Abandoned        : UChar
   +0x01d ApcDisable       : UChar

+0x010  MutantListEntry
拥有互斥体线程(KTHREAD+0x010 MutantListHead)是个链表头**圈着所有互斥体**

+0x018 OwnerThread:
正在拥有互斥体的线程 

+0x01c  Abandoned:
是否已经被放弃不用 

+0x01d ApcDisable:
是否禁用内核APC 		0不禁用 1禁用
(3环)Mutant 对应内核函数 NtCreateMutant ApcDisable = 0
(0环)Mutex 对应内核函数 NtCreateMutex ApcDisable = 1
(参见 KeWaitForsingleObject 函数)

CreateMutex创建互斥体

HANDLE CreateMutex
(
		LPSECURITYATTRIBUTE SlpMutexAttributes, //指向安全属性的指针 
		BOOL bnitialOwner, //初始化互斥对象的拥有者 
		LPCTSTR IpName //指向互斥对象名的指针 
)
参数2:TRUE代表就是当前线程的,
FALSE代表这个互斥体不是当前线程只是将他创建出来
CreateMutex -> NtCreateMutant(内核函数) -> KelnitializeMutant(内核函数)
初始化MUTANT结构体:
MUTANT.Header.Type=2;
MUTANT.Header.SianalState =binitialOwner ?0:1;//参数2初始值为true它就为0
MUTANT.OwnerThread=当前线程 or NULL;//参数2初始值为true当前线程,false就是0
MUTANT.Abandoned = 0;
MUTANT.ApcDisable=0;

如果 blnitialOwner == TRUE 将当前互斥体挂入到当前线程的互斥体链表(KTHREAD+0x010 MutantListHead)

ReleaseMutex释放临界区

BOOL WINAPI ReleaseMutex(HANDLE hMutex);

ReleaseMutex ->NtReleaseMutant ->KeReleaseMutant

正常调用时:
MUTANT.Header.SignalState++;

如果SignalState=1(有信号了) 说明其他进程可用了 将该互斥体从线程链表中移除。

互斥体解决等待对象被遗弃问题

_KMUTANT
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListEntry  : _LIST_ENTRY
   +0x018 OwnerThread      : Ptr32 _KTHREAD	//当前互斥体对象所属线程
   +0x01c Abandoned        : UChar
   +0x01d ApcDisable       : UChar

+0x010 MutantListEntry:
拥有互斥体线程(KTHREAD+0x010 MutantListHead)是个链表头圈着所有互斥体 

+0x01c Abandoned:
是否已经被放弃不用

MmUnloadSystemlmage -> KeReleaseMutant(X, Y,Abandon,Z)//是否被丢弃

KeReleaseMutant的第3个参数可以知道是被正常释放,还是被丢弃的
正常是FALSE
丢弃是TRUE,系统会直接将SignalState置为有信号状态

if(Abandon == false) //正常调用 
{
	MUTANT.Header.SignalState++;
}else//丢弃
{
	MUTANT.Header.SignalState == 1;
	MUTANT.OwnerThread == NULL;
}
if(MUTANT.Header.SignalState==1)
{
	MUTANT.OwnerThread == NULL;
	//从当前线程互斥体链表中将当前互斥体移除
}

在这里插入图片描述

进入互斥体
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值