C# Monitor的Wait和Pulse方法使用详解
【转载】http://blog.csdn.net/qqsttt/article/details/24777553
Monitor的Wait和Pulse方法在线程的同步锁使用中是比较复杂的,理解稍微困难些,但也是内涵相当丰富和
微妙的!通过他们你可以自己实现AutoResetEvent,ManualResetEvent等同步对象,同时还会在效率和内存
使用上有个质的提高!
今天在MSDN查阅Monitor对象时,发现其下的成员方法的Demo都是用一个安全的同步Queue来阐述的,但是
代码注解和本身MSDN的专业术语晦涩难懂,造成这个实例并不是好理解,这里我将注释都添加到了关键语句上,
同时最后结合代码分析这个同步Queue是如何在Monitor的Wait和Pulse的指导下工作的:
现在我对整个代码做一个流程分析:
在这个特定背景下,线程优先顺序: 【等待队列】->【就绪队列】->【拥有锁线程】这个是重点,下文多
次会提到,其中的微妙关系的核心也来源于这个执行顺序。
MSDN官方备注:同步的对象包含若干引用,其中包括对当前拥有锁的线程的引用、对就绪队列的引
用和对等待队列的引用。
我的提醒:竞争对象锁的线程都是处于就绪队列中。
在本案例中我将FirstThread和SecondThread方法看成是A,B线程(这是完全可以的,因为A,B是两个线程的
回调函数都是同级的工作者线程),
下面是分析步骤:
/*情形1:假设A线程获取了m_smplQueue同步对象锁:
* 1、开始循环,调用Monitor.Wait(m_smplQueue):A线程释放自己对同步对象的锁,流放自己到
等待队列(B线程一开始就竞争同步锁所以处于就绪队列中),直到自己再次获得锁,否则一直阻塞。
所以A线程运行到这里就暂停了。
* 2、这时候B直接从就绪队列出来获得了m_smplQueue对象锁,Monitor.Pulse(m_smplQueue):执
行时,会将A线程放行到就绪队列,A准备获取对锁的拥有权。
* 3、执行循环,Monitor.Wait(m_smplQueue, 1000):B线程将自己流放到等待队列并释放自身对
同步锁的独占,该等待设置了1S的超时值,当B线程在1S之内没有再次获取到锁则自动添加到就绪
队列,或者这期间收到Pulse的脉冲信号。
* 4、B线程由于1S之内都返回false,lock块迅速结束,也即退出对m_smplQueue独占权,A由就绪
队列中进入对m_smplQueue的独占、继续.
* 5、在1中陈述的Monitor.Wait(m_smplQueue)的阻塞结束,返回true,执行接下来的代码:
m_smplQueue.Enqueue(counter)向队列中加入元素,执行下一行的Monitor.Pulse(m_smplQueue),
由于第3条的1S没到(我相信地球上目前已没有这么慢的CPU了),B线程收到脉冲,将自己添加到就
绪队列,counter计数+1,A线程的lock结束,A则进入等待队列.
* 6、由于B从就绪队列再次获得独占权,Monitor.Wait(m_smplQueue, 1000)返回true,while进入循
环内部,弹出第一条元素,打印出来。 调用Monitor.Pulse(m_smplQueue)将A线程加入到就绪队列,
同时while结束,lock块结束,B退出对对象锁的独占进入到等待队列中.
* 7、A继续,遵循这个规律循环往复知道所有的数被打印出来...
*
* 情形2:B线程先获取了m_smplQueue同步对象锁:
* 1、进入lock块,Monitor.Pulse(m_smplQueue)执行:由于当前的A线程已经处于就绪队列
所以收到也没作用(那么你肯定再问那这句有什么用啊?没错是得问,你发现没如果是A线程开始是
否就有用了啊!这就是它的作用!).
* 2、开始while (Monitor.Wait(m_smplQueue, 1000))中的判断,技术细节还是遵循上面所讲的,B这时
候会自动将自己流放到等待队列并在这里阻塞(也许1S到期了也会将它放置到就绪队列中去,这个作用
主要是防止死锁,因为咱们的就绪队列可不能为空啊,这在上面我忘了讲了这里补充下),于是乎A
获得了m_smplQueue独占权,于是乎又回到了上面从A先获得线程锁的流程....
*
* 总之,这个操作目的是让多个线程操作一个Queue时,保持同步:不能在无数据时出队,一旦有
一个数据就马上可以出队,最终的效果是没有一个元素在队列中。
*/
C# Monitor的Wait和Pulse方法使用详解的更多相关文章
- CentOS 6.3下Samba服务器的安装与配置方法(图文详解)
这篇文章主要介绍了CentOS 6.3下Samba服务器的安装与配置方法(图文详解),需要的朋友可以参考下 一.简介 Samba是一个能让Linux系统应用Microsoft网络通讯协议的软件, ...
- jQuery操纵DOM元素属性 attr()和removeAtrr()方法使用详解
jQuery操纵DOM元素属性 attr()和removeAtrr()方法使用详解 jQuery中操纵元素属性的方法: attr(): 读或者写匹配元素的属性值. removeAttr(): 从匹配的 ...
- php课程---Windows.open()方法参数详解
Window.open()方法参数详解 1, 最基本的弹出窗口代码 window.open('page.html'); 2, 经过设置后的弹出窗口 window.open('page.html ...
- Window.open()方法参数详解
Window.open()方法参数详解 1, 最基本的弹出窗口代码 window.open('page.html'); 2, 经过设置后的弹出窗口 window.open('page.html ...
- 集合类 Contains 方法 深入详解 与接口的实例
.Net 相等性:集合类 Contains 方法 深入详解 http://www.cnblogs.com/ldp615/archive/2009/09/05/1560791.html 1.接口的概念及 ...
- [转]js中几种实用的跨域方法原理详解
转自:js中几种实用的跨域方法原理详解 - 无双 - 博客园 // // 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同 ...
- C#虚方法virtual详解
转: http://www.cnblogs.com/jason_yjau/archive/2009/08/25/1553949.html C#虚方法virtual详解 在C++.Java等众多OOP语 ...
- JQuery动画animate的stop方法使用详解
JQuery动画animate的stop方法使用详解 animate语法: 复制代码 代码如下: $(selector).animate(styles,speed,easing,callback) 复 ...
- Linux NFS服务器的安装与配置方法(图文详解)
这篇文章主要介绍了Linux NFS服务器的安装与配置方法(图文详解),需要的朋友可以参考下(http://xb.xcjl0834.com) 一.NFS服务简介 NFS 是Network File S ...
随机推荐
- win10下安装scala流程及问题
第一步:Java 设置 检测方法前文已说明,这里不再描述. 如果还为安装,可以参考我们的Java 开发环境配置. 接下来,我们可以从 Scala 官网地址 http://www.scala-lang. ...
- C语言获取系统时间的几种方式
C语言获取系统时间的几种方式 2009-07-22 11:18:50| 分类: 编程学习 |字号 订阅 C语言中如何获取时间?精度如何? 1 使用time_t time( time_t * ...
- Office 365 企业应用以及服务概览 分享记录
博客地址:http://blog.csdn.net/FoxDave 分享时间: 2017年9月14日 分享地点: 部门内部 参与人数: 16人 分享内容: 讲解微软MVP项目计划的相关内容:讲解O ...
- docker从初识到深入
1:使用docker有哪些优势: 更快交付你的应用(Faster delivery of your applications) 让部署和测试更简单(Deploying and scaling more ...
- 20165214 实验一 Java开发环境的熟悉
20165214 实验一 Java开发环境的熟悉 一.实验报告封面 课程:Java程序设计 班级:1652班 姓名:朱文远 学号:20165214 指导教师:娄嘉鹏 实验日期:2018年4月2日 实验 ...
- 『转』android官网翻译好的蓝牙API接口说明
Develop API Guides 连接 蓝牙 本文内容 基础知识 蓝牙权限 设置蓝牙 查找设备 查询配对的设备 发现设备 连接设备 连接为服务器 连接为客户端 管理连接 使用配置文件 供应商特定的 ...
- error_log
对于我们做php开发的人员,上了生产环境,一定要把相关debug,display_errors错误提示等关掉.谁还难免不犯个错呢?这样能防止非致命性报错下,导致项目路径.数据库等信息泄漏. 问:那么问 ...
- VB识别分隔符
strTypeEx = ReadIniFile("Type", "Type", App.Path & "\set.ini") str ...
- git 清空缓冲区
git rm与git rm --cached 当我们需要删除暂存区或分支上的文件, 同时工作区也不需要这个文件了, 可以使用 git rm file_path git commit -m 'delet ...
- 重启uwsgi脚本备份
NAME="identifyImg_uwsgi.init" if [ ! -n "$NAME" ];then echo "no arguments&q ...