c#中利用 AutoResetEvent和ManualResetEvent实现线程同步

概念:

   线程的本质
  线程不是一个计算机硬件的功能,而是操作系统提供的一种逻辑功能,线程本质上是进程中一段并发运行的代码,所以线程需要操作系统投入CPU资源来运行和调度。

    线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。

    线程同步是多个线程同时访问同一资源,等待资源访问结束,浪费时间,效率低    线程异步:访问资源时在空闲等待时同时访问其他资源,实现多线程机制。

  c#中使用 AutoResetEvent和 AutoResetEvent

 AutoResetEvent 和  ManualResetEvent

   1. 都是通过将布尔值传递给构造函数来控制 初始状态,如果初始状态处于终止状态此时线程继续运行,为true,允许线程继续; ;否则为false。,事件状态为非终止,线程  阻塞。

   2.AutoResetEvent与ManualResetEvent的区别

   他们的用法\声明都很类似,Set方法将信号置为发送状态 Reset方法将信号置为不发送状态WaitOne等待信号的发送。其实,从名字就可以看出一个手动,
一个自动,这个手动和自动实际指的是在Reset方法的处理上,如下面例子:

   public AutoResetEvent autoevent=new AutoResetEvent(true);
   public ManualResetEvent manualevent=new ManualResetEvent(true);

   默认信号都处于发送状态,

    autoevent.WaitOne();
   manualevent.WaitOne();

    如果 某个线程调用上面该方法,则当信号处于发送状态时,该线程会得到信号,得以继续执行。差别就在调用后,autoevent.WaitOne()每次只允许一个线程
   进入,当某个线程得到
号(也就是有其他线程调用了autoevent.Set()方法后)后,autoevent会自动又将信号置为不发送状态,则其他调用WaitOne的线程只
   有继续等待.也就是说,autoevent一次只唤醒一个线程。而manualevent则可以唤醒多个线程,因为当某个线程调用了set方法后,其他调用waitone的线程
   获得信号得以继续执行,而manualevent不会自动将信号置为不发送.也就是说,除非手工调用了manualevent.Reset().方法
,则manualevent将一直保持有信号状态,manualevent也就可以同时唤醒多个线程继续执行。如果上面的程序换成ManualResetEvent的话,就需要在waitone后面做下reset。

 3 线程数据传输过后,线程需要返回false状态,此时信号可发送。数据传输时状态为true状态,数据不可发送。

using System;
using System.Threading;

class CalculateTest
{
    static void Main()
    {
        Calculate calc = new Calculate();
        Console.WriteLine("Result = {0}.",
            calc.Result(234).ToString());
        Console.WriteLine("Result = {0}.",
            calc.Result(55).ToString());
    }
}

class Calculate
{
    double baseNumber, firstTerm, secondTerm, thirdTerm;
    AutoResetEvent[] autoEvents;
    ManualResetEvent manualEvent;

    // Generate random numbers to simulate the actual calculations.
    //声明随机数
    Random randomGenerator;

    public Calculate()
    {
        autoEvents = new AutoResetEvent[]
        {
            new AutoResetEvent(false),//初始化设置事件状态为非终止(信号状态为可发送),线程被阻止
            new AutoResetEvent(false),
            new AutoResetEvent(false)
        };

        manualEvent = new ManualResetEvent(false);//初始化设置事件状态为非终止(信号状态为可发送),线程被阻止
    }

    void CalculateBase(object stateInfo)
    {
        baseNumber = randomGenerator.NextDouble();

        // Signal that baseNumber is ready.
        //数据源准备
        manualEvent.Set();//设置事件状态终止也就是信号不发送,线程继续运行。
    }

    // The following CalculateX methods all perform the same
    // series of steps as commented in CalculateFirstTerm.

    void CalculateFirstTerm(object stateInfo)
    {
        // Perform a precalculation.
        double preCalc = randomGenerator.NextDouble();

        // Wait for baseNumber to be calculated.
        manualEvent.WaitOne();//   manualEvent初始状态为非终止状态,即阻止线程,信号可发送,此处设置等待信号

        // Calculate the first term from preCalc and baseNumber.
        firstTerm = preCalc * baseNumber *
            randomGenerator.NextDouble();

        // Signal that the calculation is finished.
        autoEvents[0].Set();//设置事件状态为终止状态,信号不可发送,线程继续运行
    }

    void CalculateSecondTerm(object stateInfo)
    {
        double preCalc = randomGenerator.NextDouble();
        manualEvent.WaitOne();
        secondTerm = preCalc * baseNumber *
            randomGenerator.NextDouble();
        autoEvents[1].Set();
    }


    void CalculateThirdTerm(object stateInfo)
    {
        double preCalc = randomGenerator.NextDouble();
        manualEvent.WaitOne();
        thirdTerm = preCalc * baseNumber *
            randomGenerator.NextDouble();
        autoEvents[2].Set();
    }

    public double Result(int seed)
    {
        randomGenerator = new Random(seed);

        // Simultaneously calculate the terms.
        //同步执行运算
        ThreadPool.QueueUserWorkItem(
            new WaitCallback(CalculateBase));
        ThreadPool.QueueUserWorkItem(
            new WaitCallback(CalculateFirstTerm));
        ThreadPool.QueueUserWorkItem(
            new WaitCallback(CalculateSecondTerm));
        ThreadPool.QueueUserWorkItem(
            new WaitCallback(CalculateThirdTerm));

        // Wait for all of the terms to be calculated.
        //autoEvent为true则表示set()与waitone()之间代码已经执行,后面三个线程会自动返回阻塞状态,
        WaitHandle.WaitAll(autoEvents);

        // Reset the wait handle for the next calculation.
        manualEvent.Reset();
        //将第一个线程设置为阻塞状态。
        return firstTerm + secondTerm + thirdTerm;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值