Wait() 和 Pulse() 机制用于线程间交互。当在一个对象上使用Wait() 方法时,访问这个对象的线程就会一直等待直到被唤醒。Pulse() 和 PulseAll() 方法用来通知等待的线程醒来的。下面是关于Wait() 和 Pulse() 方法如何运行的例子,WaitAndPulse.cs:

Wait() 和 Pulse() 方法仅可以在Enter() 和 Exit() 代码块内部

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Threading;
  7. namespace ThreadEx
  8. {
  9. public class LockMe
  10. {
  11. }
  12. class WaitPalsel
  13. {
  14. private int result = 0;
  15. private LockMe lM;
  16. public WaitPalsel(LockMe l)
  17. {
  18. this.lM = l;
  19. }
  20. public void CriticalSection()
  21. {
  22. Monitor.Enter(this.lM);
  23. Console.WriteLine("WaitPulse1: Entered Thread " + Thread.CurrentThread.GetHashCode());
  24. for (int i = 1; i <= 5; i++)
  25. {
  26. Monitor.Wait(this.lM);
  27. Console.WriteLine("WaitPulse1: Result =" + result++ + "ThreadID"
  28. + Thread.CurrentThread.GetHashCode());
  29. Monitor.Pulse(this.lM);
  30. }
  31. Console.WriteLine("WaitPulse1: Exiting Thread " + Thread.CurrentThread.GetHashCode());
  32. Monitor.Exit(this.lM);
  33. }
  34. }
  35. class WaitPulse2
  36. {
  37. private int result = 0;
  38. private LockMe lM;
  39. public WaitPulse2()
  40. { }
  41. public WaitPulse2(LockMe l)
  42. {
  43. this.lM = l;
  44. }
  45. public void CriticalSection()
  46. {
  47. Monitor.Enter(this.lM);
  48. Console.WriteLine("WaitPulse2: Entered Thread " + Thread.CurrentThread.GetHashCode());
  49. for (int i = 1; i < 5; i++)
  50. {
  51. Monitor.Pulse(this.lM);
  52. Console.WriteLine("WaitPulse2: Result ="+result++ +"ThreadID"
  53. +Thread.CurrentThread.GetHashCode());
  54. Monitor.Wait(this.lM);
  55. Console.WriteLine("WaitPulse2: WokeUp");
  56. }
  57. Console.WriteLine("WaitPulse2 Exiing Thread " + Thread.CurrentThread.GetHashCode());
  58. Monitor.Exit(this.lM);
  59. }
  60. }
  61. class Program
  62. {
  63. static void Main(string[] args)
  64. {
  65. LockMe l = new LockMe();
  66. WaitPalsel e1 = new WaitPalsel(l);
  67. WaitPulse2 e2 = new WaitPulse2(l);
  68. Thread t1 = new Thread(new ThreadStart(e1.CriticalSection));
  69. t1.Start();
  70. Thread t2 = new Thread(new ThreadStart(e2.CriticalSection));
  71. t2.Start();
  72. Console.ReadLine();
  73. }
  74. }
  75. }

在Main() 方法中,我们创建了一个LockMe对象。然后创建了两个对象,WaitPulse1, WaitPulse2, 接着把它们委托给线程以便于线程可以调用这两个对象的CriticalSection()方法。注意WaitPulse1和WaitPulse2这两个对象中的LockMe实例是不同的,因为传递给对应构造函数的对象引用不同。初始化完对象以后,我们创建了两个线程t1 和 t2, 并向这两个线程分别传递各自的CriticalSection()函数。

假设WaitPulse1.CriticalSection() 先执行,线程t1 进入方法的关键部分并在锁住LockMe对象后在for循环中执行Monitor.Wait()。由于执行了Monitor.Wait(), 所以它得等待其他线程调用Monitor.Pulse()方法(一个运行时通知)来将其唤醒。我们锁住LockMe对象是因为我们只希望在任意时间仅有一个对象访问共享LockMe实例。

注意当线程执行Monitor.Wait()方法时,它会暂时释放LockMe对象上的锁,这样其他线程就可以访问LockMe对象。在线程t1进入等待状态后,线程t2可以自由地访问LockMe对象。尽管这两个线程都有自己的LockMe对象(WaitPulse1, WaitPulse2),但是它们都引用同一个对象。线程t2获得LockMe对象上的锁并进入WaitPulse2.CriticalSection()方法。当它进入for循环时,它给等待LockMe对象的线程(本例中是t1)发送一个运行时通知(Monitor.Pulse())然后进入等待状态。

最终,t1醒来并获得LockMe对象的锁。线程t1然后访问result变量并向等待LockMe对象的线程(本例中为t2)发送一个运行时通知。如此反复直到for循环结束。

如果你依据程序的输出结果来看上面的描述,那么我们说的概念会非常清晰易懂。要注意每个Enter()方法都有一个Exit()方法匹配否则程序不应该结束。

Enter()方法接受一个对象作为参数。如果参数为null 或者参数时一个方法名或者一个值类型的对象(比如int型),Enter()方法都会抛出异常。

调用。

使用线程 Monitor.Wait() 和 Monitor.Pulse()的更多相关文章

  1. C# Monitor的Wait和Pulse方法使用详解

    [转载]http://blog.csdn.net/qqsttt/article/details/24777553 Monitor的Wait和Pulse方法在线程的同步锁使用中是比较复杂的,理解稍微困难 ...

  2. 线程同步 – lock和Monitor

    在多线程代码中,多个线程可能会访问一些公共的资源(变量.方法逻辑等等),这些公共资源称为临界区(共享区):临界区的资源是不安全,所以需要通过线程同步对多个访问临界区的线程进行控制. 同样,有些时候我们 ...

  3. 多线程中的lock,Monitor.Wait和Monitor.Pulse

    我们知道lock实际上一个语法糖糖,C#编译器实际上把他展开为Monitor.Enter和Monitor.Exit,即: lock(lockObj) { //... } ////相当于(.Net4以前 ...

  4. C#的Monitor.Enter和Monitor.Exit

    C#的lock 语句实际上是调用Monitor.Enter和Monitor.Exit,中间夹杂try-finally语句的简略版,下面是实际发生在之前例 子中的Go方法: 1 2 3 4 5 6 7 ...

  5. Benchmark result without MONITOR running: Benchmark result with MONITOR running (redis-cli monitor > /dev/null): 吞吐量 下降约1半 Redis监控工具,命令和调优

    https://redis.io/commands/monitor In this particular case, running a single MONITOR client can reduc ...

  6. C# 线程同步之排它锁/Monitor监视器类

    一.Monitor类说明,提供同步访问对象的机制. 1.位于System.Threading命名空间下,mscorlib.dll程序集中. 2.Monitor通过获取和释放排它锁的方式实现多线程的同步 ...

  7. C#线程同步与死锁Monitor

    在上一讲介绍了使用lock来实现C#线程同步.实际上,这个lock是C#的一个障眼法,在C#编译器编译lock语句时,将其编译成了调用Monitor类.先看看下面的C#源代码: public stat ...

  8. 线程基础四 使用Monitor类锁定资源

    前面我们讲过了lock的用法以及竞争条件导致的错误,实际上lock关键字是Monitor类用例的一个语法糖.如果我们分解使用了lock关键字的代码,将会看到它如下面代码片段所示: bool acqui ...

  9. 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock

    [源码下载] 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLoc ...

随机推荐

  1. 洛谷P2371 [国家集训队]墨墨的等式

    P2371 [国家集训队]墨墨的等式 题目描述 墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+-+anxn=Ba_1x_1+a_2y_2+-+a_nx_n=Ba1​x1​+a2​y2​+-+a ...

  2. SaltStack远程执行Windows job程序(黑窗口)填坑经过

    近期接到领导通知,要将公司内的所有Windows服务添加到自动发布系统中,由于这种服务很多,节点分布散乱,每次都是由开发主管手动替换(虽然他们自己开发了自动打包替换工具,但仍需要一台一台登陆到服务器上 ...

  3. 廖雪峰Java13网络编程-2Email编程-2接收Email

    1接收Email协议类型 接收Email:收件人通过MUA软件把邮件从MDA抓取到本地计算机的过程. 1.1 POP3 从MUA到MDA使用最广泛的是协议是POP3 Post Office Proto ...

  4. Ubuntu安装Windows软件

    https://www.cnblogs.com/chendeqiang/p/10177530.html Windows系列软件 安装Deepin封装好的框架 git clone https://git ...

  5. 基于OneMap的水利行业共享服务平台搭建步骤

    今天上午再次学习Esri技术培训中心的“GIS服务共享与运维管理——之OneMap解决方案”课程,从中学习了OneMap的产品架构以及基于OneMap共享服务平台的搭建步骤.下面把其中水利行业的共享服 ...

  6. PHP如何打造一个高可用高性能的网站呢?

    https://blog.csdn.net/jwq101666/article/details/80162245 1. 说到高可用的话要提一下redis,用过的都知道redis是一个具备数据库特征的n ...

  7. 数据库DSN是什么

    数据库建立好之后,要设定系统的 DSN(数据来源名称),才能让网页可以知道数据库所在的位置以及数据库相关的属性.使用DSN的好处还有,如果移动数据库档案的位置,或是换成别种类型的数据库,只要重新设定 ...

  8. Java笔记 - 异常机制

    JAVA异常机制是Java提供的用于处理程序在运行期可能出现的异常事件(如数组下标越界.文件不存在等)的一种机制,使程序不会因为 异常的发生 而 阻断或产生不可预见的结果 .而且还可以将逻辑代码与错误 ...

  9. Installer - 使用Maven自动布署至外部Tomcat

    一.配置相关文件 1.配置tomcat的conf/tomcat-users.xml文件 <tomcat-users> <role rolename="manager-scr ...

  10. Cesium官方教程9--粒子系统

    原文地址:https://cesiumjs.org/tutorials/Particle-Systems-Tutorial/ 粒子系统介绍 这篇教程带你学习Cesium的粒子相关API,比如如何在你的 ...