zoukankan      html  css  js  c++  java
  • 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时,保持同步:不能在无数据时出队,一旦有
    一个数据就马上可以出队,最终的效果是没有一个元素在队列中。

     */

  • 相关阅读:
    洛谷P4550 收集邮票 期望dp
    Codeforces Round #748 (Div. 3) G. Changing Brackets
    [Codeforces Round #748 (Div. 3)](https://codeforces.com/contest/1593) F. Red-Black Number 记忆化搜索
    [Codeforces Round #748 (Div. 3)](https://codeforces.com/contest/1593) D2 Half of Same
    HDU 3746 Cyclic Nacklace kmp找循环节
    Codeforces Round #747 (Div.2) D. The Number of Imposters
    Nand2tetris 学习笔记
    怎样解题表
    [省选]知识点板块
    List of Problems to be Solved
  • 原文地址:https://www.cnblogs.com/yy1234/p/8329038.html
Copyright © 2011-2022 走看看