Windows系统编程C/C++--互斥量

目录

1.互斥量内核对象

2.遗弃问题


在用户模式下进行线程同步的最大的好处就是速度快。如果关心应用程序性能问题,那么应该先考虑用户模式下的同步机制是否适用。但是同时也存在局限性,对于一些函数只能对一个值进行操作,他们从来不会将线程切换到等待状态。因此我们可以用关键段来把线程切换到等待状态,但是只能对待同一个进程中的线程进行同步。除此之外还容易陷入死锁状态,只是因为我们无法进入关键段指定一个最长时间。

对于线程同步来说,这些内核对象中的每一种要么处于触发状态,要么处于未触发状态。在进程内核对象的内部有一个布尔变量,当系统创建内核对象的时候会把这个变量的初始值设置为FALSE(未触发);当进程终止时,操作系统会自动将内核对象中的这些布尔值设置为TURUE,标识该对象已经触发。Windows提供帮助进程线程同步的内核对象:事件,可等待计时器,信号量以及互斥量。

1.互斥量内核对象

它用来确保一个线程独占一个资源的访问。互斥量内核对象包含一个使用计数,线程ID以及一个递归计数。互斥量与关键段的行为完全相同,不同之处是关键段时用火模式下的同步对象,而互斥量是内核对象。这就意味着不同进程中的线程可以访问一个互斥量,且在等待对资源的访问全是指定一个最长等待时间。

线程ID用来标识当前占用这个互斥量的是系统中的哪个线程,递归计数器表示这个线程占用该互斥量的次数。

下面先说明一下创建互斥量的函数:

  • CreateMutex()
HANDLE CreateMutex(
    PSECURITY_ATTRIBUTES psa,
    BOOL bInitialOwner,
    PCTSTR pszName
);

psa:指向对象的指针

bInitialOwer:初始互斥化对象的所有者

pszname:指向互斥对象的指针

  • CreateMutexEx()

我们也可以直接使用CreateMutexEx()在dwDesiredAccess参数中指定访问权限。参数dwFlags代替了CreateMutex()函数中参数bInitialOwned:0表示FALSE,CREATE_MUTEX_INITIAL_OWNER等价与TRUE。

HANDLE CreateMutex(
    PSECURITY_ATTRIBUTES psa,
    PCTSTR pszName
    DWORD dwFlags,
    DWORD dwDesiredAccess
);
  • OpenMutex()

我们也可以调用OpenMutex()函数来得到一个一个已经存在的互斥量的句柄,该句柄与当前进程相关。

HANDLE OpenMutex(
	DWORD dwDesiredAccess,
	BOOL bInheritHandle,
	PCTSTR pszName
	);

bInitialOwner是用来控制互斥量的初始状态,如果传的时FALSE(通常情况),则互斥量对象的线程ID和递归计数器都将被设置成0.这就意味这互斥量不为任何线程占用,因此处于触发状态如果给他传TRUE,那么对象的线程ID将被设置为调用线程的线程ID,递归技术将被设置成1,由于线程ID为非零值,因此互斥量最初处于未触发状态

为了获得被保护资源的访问权限,线程要调用一个等待函数并出入互斥量的句柄。在内部等待函数会检查线程ID是否为0(此时,互斥量处于触发状态)。如果0,则函数会把线程ID设为调用线程ID,把递归计数设置为1,然后让调用线程继续运行。

如果等待函数检测到线程ID不为0(互斥量处于未触发状态),那么调用线程将进入等待状态。当另一个线程将互斥量的线程的线程ID设置为0的时候,系统会记得有一个线程正在等待,于是会把线程ID设置为正在等待的ID,把递归计数设置为1,如果为0,那么函数会把线程ID设置为正在等待的那个线程ID,把递归技术设置为1,使用正在等待的线程变成可调度状态。这些对互斥量内核对象的检查和修改都是以原子方式进行的。

注意:在用来出发普通内核对象和撤销触发普通内核对象的规则中,有一条不适用于互斥量,要注意。假设线程试图登海一个未触发的互斥量对象,在这种情况下,线程通常会进入等待状态。但是系统会检查想要获得互斥量的线程ID与互斥量对象内部记录的线程ID是否相同。如果线程ID一致,则系统会让线程保持可调度状态,即是该互斥量尚未触发。此时是与其他不同的,每次线程成功等待了一个互斥量,互斥量对象的递归计数会递增,使递归计数大于1的唯一途径是利用这个例外,让线程多次等待同一个互斥量。

 当成功的等到了互斥量,线程就知道自己已经独占了对受保护资源的访问。任何试图(通过等待互斥量)后去对资源的访问权限的线程将进入等待状态。当目前占有访问权限的线程不再需要访问资源的时候,它必须调用RealseMutex函数来进行释放互斥量,这个函数会将对象的递归计数减一,如果线程成功等待了互斥量互斥量对象不止一次那么线程必须调用ReleaseMutex相同的次数才能使用对象的递归计数变成0.当地贵计数变成0的时候,函数还会将线程ID设为0,这样就触发了对象。

当对象被触发的时候,系统会自动检查有没有其他线程正在等待该互斥量,如果有,那么系统会选择一个正在等待的线程,把互斥量的所有权给他。这就意味着把对象内部的线程ID设为所有选择的那个线程ID,并把递归计数器设置为1;如果没有线程在等待会吃凉,那么互斥量会保持在触发状态,这样下一个等待他的线程就可以立即得到它。

2.遗弃问题

互斥量它具有线程所有权,他即使在未触发状态下也能为线程所获取,它不仅仅适用于试图获取互斥量的线程,也适用于试图释放互斥量的线程。
 使用RealseMutex函数进程释放,函数会检查调用线程的线程ID与互斥量内部保存的线程ID是否一致。如果一致,则递归计数会递减。如果不一致,则函数将不执行任何操作并返回FALSE,这是调用GetLastError()会返回ERROR_NOT_OWNER。
 此时如果占用互斥量的线程在释放互斥量之前终止,那么对互斥量和正在等待该互斥量的线程来说,系统会认为互斥量被遗弃,由于占用他的线程提前终止,无法进行释放此互斥量。系统会记录所有互斥量和线程内核对象,因此他知道互斥量被遗弃后,会将互斥量对象的线程ID设置为0,将他的递归计数设置为0,然后系统会检查有没有其他线程正在等待该互斥量,如果有,把对象内部的线程ID设置为现在线程的ID,并将递归计数设置为1,这样备选的线程就变成可调度状态。唯一不同的是等待函数不在返回通常的WAIT_OBJECT_0,而是返回一个特殊的值WAIT_ABANDONED。这个返回值表示线程正在等待的互斥量为其他线程所占用,但线程完成对共享资源的使用之前终止了。刚获得互斥量的线程并不知道资源现在处于什么状态, 他可能已经被完全损坏了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值