本篇通过互斥量来解决线程的同步,学习其中的一些知识。

互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问。互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源。使用互斥量Mutex主要将用到四个函数。下面是这些函数的原型和使用说明。

第一个 CreateMutex
函数功能:创建互斥量(注意与事件Event的创建函数对比)
函数原型:
HANDLECreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,     LPCTSTR lpName
);
函数说明:
第一个参数表示安全控制,一般直接传入NULL。
第二个参数用来确定互斥量的初始拥有者。
如果传入TRUE表示互斥量对象内部会记录创建它的线程的线程ID号并将递归计数设置为1,
由于该线程ID非零,所以互斥量处于未触发状态。
如果传入FALSE,那么互斥量对象内部的线程ID号将设置为NULL,递归计数设置为0,
这意味互斥量不为任何线程占用,处于触发状态。
第三个参数用来设置互斥量的名称,在多个进程中的线程就是通过名称来确保它们访问的是同一个互斥量。
函数访问值:
成功返回一个表示互斥量的句柄,失败返回NULL。

注意区分触发状态和非触发状态:触发状态就是线程不会在这里阻塞,或者由原来的不可用变为了可用,去唤醒等待的线程。

第二个打开互斥量
函数原型:
HANDLEOpenMutex(DWORD dwDesiredAccess,BOOL bInheritHandle,LPCTSTR lpName     //名称
);
函数说明:
第一个参数表示访问权限,对互斥量一般传入MUTEX_ALL_ACCESS。详细解释可以查看MSDN文档。
第二个参数表示互斥量句柄继承性,一般传入TRUE即可。
第三个参数表示名称。某一个进程中的线程创建互斥量后,其它进程中的线程就可以通过这个函数来找到这个互斥量。
函数访问值:
成功返回一个表示互斥量的句柄,失败返回NULL。

第三个触发互斥量
函数原型:
BOOLReleaseMutex (HANDLEhMutex)
函数说明:
访问互斥资源前应该要调用等待函数,结束访问时就要调用ReleaseMutex()来表示自己已经结束访问,
其它线程可以开始访问了。

最后一个清理互斥量
由于互斥量是内核对象,因此使用CloseHandle()就可以(这一点所有内核对象都一样)。


接下来我们就在经典多线程问题用互斥量来保证主线程与子线程之间的同步,由于互斥量的使用函数类似于事件Event,所以可以仿照上一篇的实现来写出代码:

#include <stdio.h>
#include <process.h>
#include <windows.h>int g_num;
//互斥量和关键段
HANDLE g_hThreadParam;
CRITICAL_SECTION g_csThreadCode;
const int THREAD_NUM = 10;unsigned int __stdcall Fun(void *param)
{int n_thread_num = *(int*)param;//触发互斥量ReleaseMutex(g_hThreadParam);Sleep(50);EnterCriticalSection(&g_csThreadCode);g_num++;Sleep(0);printf("线程编号为%d 全局变量值为%d\n", n_thread_num, g_num);LeaveCriticalSection(&g_csThreadCode);return 0;
}int main(void)
{//初始化互斥量与关键段 第二个参数为true表示互斥量为创建线程所有g_hThreadParam = CreateMutex(NULL, false, NULL);InitializeCriticalSection(&g_csThreadCode);HANDLE handle[THREAD_NUM];int i = 0;g_num = 0;while (i < THREAD_NUM){handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);//在访问互斥资源前,调用等待函数,等待互斥量被触发WaitForSingleObject(g_hThreadParam, INFINITE);++i;}WaitForMultipleObjects(THREAD_NUM, handle, true, INFINITE);//销毁互斥量和关键段CloseHandle(g_hThreadParam);DeleteCriticalSection(&g_csThreadCode);for (i = 0; i < THREAD_NUM; i++){CloseHandle(handle[i]);}return 0;
}

  执行结果图:

可以看出,与关键段类似,互斥量也是不能解决线程间的同步问题

联想到关键段会记录线程ID即有“线程拥有权”的,而互斥量也记录线程ID,莫非它也有“线程拥有权”这一说法。

答案确实如此,互斥量也是有“线程拥有权”概念的。“线程拥有权”在关键段中有详细的说明,这里就不再赘述了。另外由于互斥量常用于多进程之间的线程互斥,所以它比关键段还多一个很有用的特性——“遗弃”情况的处理。比如有一个占用互斥量的线程在调用ReleaseMutex()触发互斥量前就意外终止了(相当于该互斥量被“遗弃”了),那么所有等待这个互斥量的线程是否会由于该互斥量无法被触发而陷入一个无穷的等待过程中了?这显然不合理。因为占用某个互斥量的线程既然终止了那足以证明它不再使用被该互斥量保护的资源,所以这些资源完全并且应当被其它线程来使用。因此在这种“遗弃”情况下,系统自动把该互斥量内部的线程ID设置为0,并将它的递归计数器复置为0,表示这个互斥量被触发了。然后系统将“公平地”选定一个等待线程来完成调度(被选中的线程的WaitForSingleObject()会返回WAIT_ABANDONED_0)。


下面写二个程序来验证下:

第一个程序创建互斥量并等待用户输入后就触发互斥量。第二个程序先打开互斥量,成功后就等待并根据等待结果作相应的输出:

第一个进程代码:

#include <stdio.h>
#include <conio.h>
#include <windows.h>const char mutex_name[] = "MUTEX_NAME";int main(void)
{HANDLE hMutex = CreateMutex(NULL, true, mutex_name);printf("互斥量已经创建,显现按任意键触发互斥量\n");getch();exit(0);ReleaseMutex(hMutex);printf("互斥量已经触发");CloseHandle(hMutex);return 0;
}

第二个进程代码:  

#include <stdio.h>
#include <windows.h>const char mutex_name[] = "MUTEX_NAME";
int main()
{HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, true, mutex_name);if (hMutex == NULL){printf("打开互斥量失败\n");return 0;}printf("等待中...\n");DWORD dwResult = WaitForSingleObject(hMutex, INFINITE);//等待互斥量被触发switch (dwResult){case WAIT_ABANDONED:printf("拥有互斥量的进程意外终止\n");break;case WAIT_OBJECT_0:printf("已经收到信号\n");break;case WAIT_TIMEOUT:printf("信号未在规定的时间内送到\n");break;}CloseHandle(hMutex);return 0;
}

运用这二个程序时要先启动程序一再启动程序二。下面展示部分输出结果:

结果一:两个进程顺利执行完毕:

结果二:将进程一中//exit(0);前面的注释符号去掉,这样程序一在触发互斥量之前就会因为执行exit(0);语句而且退出,程序二会收到WAIT_ABANDONED消息并输出“拥有互斥量的进程意外终止”:

有这个对“遗弃”问题的处理,在多进程中的线程同步也可以放心的使用互斥量。


最后总结下互斥量Mutex:

1.互斥量是内核对象,它与关键段都有“线程所有权”所以不能用于线程的同步。

2.互斥量能够用于多个进程之间线程互斥问题,并且能完美的解决某进程意外终止所造成的“遗弃”问题。

转载于:https://www.cnblogs.com/stemon/p/4855265.html

[一个经典的多线程同步问题]解决方案三:互斥量Mutex相关推荐

  1. [一个经典的多线程同步问题]解决方案一:关键段CS

    前面提出了一个经典的多线程同步互斥问题,本篇将用关键段CRITICAL_SECTION来尝试解决这个问题. 本文先介绍如何使用关键段,然后再深层次的分析下关键段的实现机制和原理. 关键段CRITICA ...

  2. 一个经典的多线程同步问题

    本篇文章参考了http://blog.csdn.net/morewindows/article/details/7442333 程序描述: 主线程启动10个子线程并将表示子线程序号的变量地址作为参数传 ...

  3. C#线程同步(3)- 互斥量 Mutex

    什么是Mutex "mutex"是术语"互相排斥(mutually exclusive)"的简写形式,也就是互斥量.互斥量跟临界区中提到的Monitor很相似, ...

  4. 秒杀多线程第七篇 经典线程同步 互斥量Mutex

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...

  5. Java多线程:多线程同步安全问题的 “三“ 种处理方式 ||多线程 ”死锁“ 的避免 || 单例模式”懒汉式“的线程同步安全问题

    Java多线程:多线程同步安全问题的 "三" 种处理方式 ||多线程 "死锁" 的避免 || 单例模式"懒汉式"的线程同步安全问题 每博一文 ...

  6. 经典线程同步 互斥量Mutex的使用分析

    互斥量(mutex)内核对象用来确保一个线程独占对一个资源的访问. 互斥量对象包含一个使用计数.线程ID以及一个递归计数. 互斥量与关键段的行为完全相同.但是,互斥量是内核对象,而关键段是用户模式下的 ...

  7. Linux系统编程----16(线程同步,互斥量 mutex,互斥锁的相关函数,死锁,读写锁)

    同步概念 所谓同步,即同时起步,协调一致.不同的对象,对"同步"的理解方式略有不同.如,设备同步,是指在两 个设备之间规定一个共同的时间参考:数据库同步,是指让两个或多个数据库内容 ...

  8. windows 多线程(五) 互斥量(Mutex)

    参考:http://blog.csdn.net/morewindows/article/details/7470936 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行 ...

  9. 【C/C++多线程编程之六】pthread互斥量

    多线程编程之线程同步互斥量 Pthread是 POSIX threads 的简称,是POSIX的线程标准. Pthread线程同步指多个线程协调地,有序地同步使用共享资源.[C/C++多线程编程之五] ...

最新文章

  1. 【初识】-JUC·Executor框架
  2. Windows命令远程执行工具Winexe
  3. ansible操作远程服务器报Error: ansible requires the stdlib json or simplejson module, neither was found!...
  4. JavaWeb项目开发案例精粹-第6章报价管理系统-001需求分析及设计
  5. r语言中paste函数_R中的paste()函数-简要指南
  6. *BZOJ2330: [SCOI2011]糖果
  7. SD nand flash 简单的读写速度测试
  8. 仿剩余金额宝数字渐慢跳动效果
  9. iOS9获取手机序列号serialNumber(UDID)
  10. Pandas之skew,求偏度
  11. 单点登录 SSO 解决方案选型指南|身份云研究院
  12. 2014 青年歌手大奖赛_评委会打分
  13. jupyter(ipython)内嵌问题:%pylab inline的使用
  14. 喂养三种宠物:猫、狗和鸟
  15. 某系统采用基于优先权的非抢占式进程调度策略,完成一次进程调度和进程切换的系统时间开销为 1μs。
  16. 操作系统笔记(3)——同步与互斥
  17. CSS学习笔记1(2020年11月)
  18. 我是如何保护 70000 ETH 并赢得 600 万漏洞赏金的
  19. 奥的斯OTIS电梯电气原理图一般讲解通则-识图
  20. (16)调度代码周期性运行

热门文章

  1. 超维计算让AI有记忆和反应,还能解决自动驾驶难题
  2. 无人驾驶产业发展现状及影响
  3. 国际基因编辑科技发展报告
  4. 同为 Java 开发:有了这些 Java 项目经历,面大厂稳了!
  5. 计算机科班学习 OS 的正确姿势!
  6. 2020 年最强大的 10 门编程语言
  7. 技术人的不惑之路...... | 每日趣闻
  8. 互联网人的生存指南 | 每日趣闻
  9. bos开发时,测试卡在登录界面解决
  10. ZooKeeper基础学习