秒杀多线程-互斥量Mutex
推荐阅读:



函数的原型和使用说明
CreateMutex()
函数功能:创建互斥量(注意与事件Event的创建函数对比)
函数原型:
函数说明:第一个参数表示安全控制,一般直接传入NULL。
第二个参数用来确定互斥量的初始拥有者。如果传入TRUE表示互斥量对象内部会记录创建它的线程的线程ID号并将递归计数设置为1,由于该线程ID非零,所以互斥量处于未触发状态。如果传入FALSE,那么互斥量对象内部的线程ID号将设置为NULL,递归计数设置为0,这意味互斥量不为任何线程占用,处于触发状态。
第三个参数用来设置互斥量的名称,在多个进程中的线程就是通过名称来确保它们访问的是同一个互斥量。如果 lpName
与现有命名互斥对象的名称匹配,则此函数将请求MUTEX_ALL_ACCESS访问权限。在这种情况下,将忽略 bInitialOwner
参数,因为它已由创建过程设置。如果 lpMutexAttributes
参数不是 NULL,则确定是否可以继承句柄,但忽略其安全描述符成员。
如果 lpName
为 NULL,则创建互斥对象时没有名称。
如果 lpName
与现有事件、信号量、可等待计时器、作业或文件映射对象的名称匹配,则该函数将失败,并且 GetLastError
函数将返回ERROR_INVALID_HANDLE。发生这种情况是因为这些对象共享相同的命名空间。
返回值:成功返回一个表示互斥量的句柄,失败返回NULL
OpenMutex()
函数功能:打开互斥量
函数原型:
函数说明:
MUTEX_ALL_ACCESS。
第二个参数表示互斥量句柄继承性,一般传入TRUE即可。
第三个参数表示名称。某一个进程中的线程创建互斥量后,其它进程中的线程就可以通过这个函数来找到这个互斥量。
返回值:成功返回一个表示互斥量的句柄,失败返回NULL
ReleaseMutex()
函数功能:释放指定互斥锁对象的所有权
函数原型:
函数说明:
如果调用线程不拥有互斥对象,则 ReleaseMutex()
函数将失败。访问互斥资源前应该要调用等待函数,结束访问时就要调用ReleaseMutex()
来表示自己已经结束访问,其它线程可以开始访问了。
最后一个清理互斥量
由于互斥量是内核对象,因此使用CloseHandle()
就可以(这一点所有内核对象都一样)。
仿造事件Event写代码

可以看出,与关键段类似,互斥量也是不能解决线程间的同步问题。
联想到关键段会记录线程ID即有“线程拥有权”的,而互斥量也记录线程ID,莫非它也有“线程拥有权”这一说法。
答案确实如此,互斥量也是有“线程拥有权”概念的。“线程拥有权”在关键段中有详细的说明,这里就不再赘述了。另外由于互斥量常用于多进程之间的线程互斥,所以它比关键段还多一个很有用的特性——“遗弃”情况的处理。比如有一个占用互斥量的线程在调用ReleaseMutex()
触发互斥量前就意外终止了(相当于该互斥量被“遗弃”了),那么所有等待这个互斥量的线程是否会由于该互斥量无法被触发而陷入一个无穷的等待过程中了?这显然不合理。因为占用某个互斥量的线程既然终止了那足以证明它不再使用被该互斥量保护的资源,所以这些资源完全并且应当被其它线程来使用。因此在这种“遗弃”情况下,系统自动把该互斥量内部的线程ID设置为0,并将它的递归计数器复置为0,表示这个互斥量被触发了。然后系统将“公平地”选定一个等待线程来完成调度(被选中的线程的WaitForSingleObject()
会返回WAIT_ABANDONED_0)。
两个程序验证
首先验证事件Event
启动两个VS,运行两个程序,可以自行百度怎么运行
第一个程序:
第二个程序:
先运行第一个程序,再运行第二个程序,如果先运行第二个程序,会直接输出打开事件失败


exit(0)
注释去掉
第一个程序会因为执行exit(0)

验证互斥量Mutex
第一个程序:
第二个程序
正常执行与事件结果一样,当程序意外退出时,互斥量不会像事件一样一直等

有这个对“遗弃”问题的处理,在多进程中的线程同步也可以放心的使用互斥量。
总结互斥量Mutex
1.互斥量是内核对象,它与关键段都有“线程所有权”所以不能用于线程的同步。
2.互斥量能够用于多个进程之间线程互斥问题,并且能完美的解决某进程意外终止所造成的“遗弃”问题。
下一篇将介绍信号量Semaphore
参考:https://blog.csdn.net/morewindows/article/details/7470936