zoukankan      html  css  js  c++  java
  • 使用线程 Monitor.Wait() 和 Monitor.Pulse()

     

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

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

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

    在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()方法都会抛出异常。


    调用。

  • 相关阅读:
    自定义dialog
    利用jquery实现自动登录
    文件的上传
    一些想法
    利用ajax实现分页效果
    自动化构建工具gulp的基础了解
    javascript模块化---requirejs
    交互ajax
    聊聊javascript的事件
    谈谈bootstrap在实践中的应用
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/5469360.html
Copyright © 2011-2022 走看看