微软示例代码 for ManualResetEvent

ManualResetEvent

       用于线程同步,通知一个或多个线程某事件已经发生,通常用于一个线程执行的任务必须在其他线程的任务执行之前完成。

       状态分为两种:终止状态和非终止状态。当某一任务完成时,将ManualResetEvent设置为终止状态,这样其他等待的线程(一个或多个)将开始执行自己的任务。

       一旦它被终止,它将保持终止状态,直到它被手动重置

class Program
{
    static void Main(string[] args)
    {
        Caclultae calc = new Caclultae();
        Console.WriteLine("Result={0}", calc.result(234).ToString());
        Console.Read();
    }
}
 
/// <summary>
/// 此微软的示例写的非常浅显易懂
/// 应充分理解这些线程的工作顺序和等待节奏,以及整个程序运行流的顺序
/// </summary>
class Caclultae
{
    double baseNum, firNum, secNum, thdNum;
 
    // 这组信号灯的状态是为 WaitHandle.WaitAll(autoEvents) 准备的
    AutoResetEvent[] autoEvents;
    
    // 这个信号灯是通知所有等待线程开始工作的
    ManualResetEvent manualEvent;
 
    Random Generator;
 
    public Caclultae()
    {
        autoEvents = new AutoResetEvent[]
        {
            new AutoResetEvent(false),
            new AutoResetEvent(false),
            new AutoResetEvent(false)
        };
        manualEvent = new ManualResetEvent(false);
    }
 
    void CalBase(object stateInfo)
    {
        baseNum = Generator.NextDouble();
        Console.WriteLine("BaseNum is Ok");
        manualEvent.Set();
    }
 
    void CalFirst(object stateInfo)
    {
        double preCalc = Generator.NextDouble();
 
        manualEvent.WaitOne();
        Console.WriteLine("FirstNum begins to Calculate");
        firNum = preCalc * baseNum * Generator.NextDouble();
 
        autoEvents[0].Set();
        Console.WriteLine("FirstNum Calculates successfully");
    }
 
    void CalSec(object stateInfo)
    {
        double preCalc = Generator.NextDouble();
        manualEvent.WaitOne();
        Console.WriteLine("SecNum begins to Calculate");
        secNum = preCalc * baseNum * Generator.NextDouble();
        autoEvents[1].Set();
        Console.WriteLine("SecNum  Calculates successfully");
    }
 
    void CalThird(object stateInfo)
    {
        double preCalc = Generator.NextDouble();
        manualEvent.WaitOne();
        Console.WriteLine("ThrdNum begins to Calculate");
        thdNum = preCalc * baseNum * Generator.NextDouble();
        autoEvents[2].Set();
        Console.WriteLine("ThrdNum  Calculates successfully");
    }
 
    public double result(int seed)
    {
        Generator = new Random(seed);
        ThreadPool.QueueUserWorkItem(new WaitCallback(CalBase));
        ThreadPool.QueueUserWorkItem(new WaitCallback(CalFirst));
        ThreadPool.QueueUserWorkItem(new WaitCallback(CalSec));
        ThreadPool.QueueUserWorkItem(new WaitCallback(CalThird));
        
        // 等待指定数组中的所有元素都收到信号
        WaitHandle.WaitAll(autoEvents);
        manualEvent.Reset();
        return firNum + secNum + thdNum;
    }
}

CalFirst,CalSec,CalThird都在等待CalBase执行完成。

当CalBase计算出BaseNum的结果之后,将ManualResetEvent变量设置为终止状态,通知其他三个任务,可以执行他们自己的任务了。

CalFirst,CalSec,CalThird在分别完成自己的任务后,对自己所属的信号autoEvent数组Set()信号。

最后,WaitHandle.WaitAll(autoEvents) 条件得以满足,程序继续执行。

manualEvent.Reset() 必须手动重置 ManualResetEvent ,为下次计算做准备。

image

原文地址:https://www.cnblogs.com/SkySoot/p/2567878.html