源动力

程序在于积累和思考
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

AutoResetEvent和ManualResetEvent的区别和用法简介

Posted on 2012-02-16 10:26  老K的幸福生活  阅读(487)  评论(0编辑  收藏  举报

在.Net多线程编程中,AutoResetEvent和ManualResetEvent这两个类经常用到,用于线程之间的通信, 他们的用法很类似,但也有区别。Set方法将信号置为发送状态,Reset方法将信号置为不发送状态;WaitOne方法在无信号状态下,可以使当前线程挂起;注意这里说的是当前线程。可以通过构造函数的参数值来决定其初始状态,true表示畅通无阻的状态(signaled),线程不能阻塞,即使调用WaitOne也不能阻塞;false表示是可阻塞的状态(nonsignaled),可以调用WaitOne方法来阻塞,WaitOne方法被调用后,当前线程(即调用这个方法的线程)暂停运行(可以看做等待事件触发),直到事件被触发(即另外的线程调用了它的Set方法)。WaitOne阻塞当前线程直到别的线程调用Set方法,但只有ManualResetEvent的状态是可阻塞(nonsignaled)时,WaitOne才能真正的起到作用。不管之前是什么状态,调用Reset都把状态设置为阻塞的(nonsignaled)。其区别就在调用后,AutoResetEvent.WaitOne()每次只允许一个线程进入,当某个线程得到信号后,AutoResetEvent会自动又将信号置为不发送状态,则其他调用WaitOne的线程只有继续等待.也就是说,AutoResetEvent一次只唤醒一个线程;而ManualResetEvent则可以唤醒多个线程,因为当某个线程调用了ManualResetEvent.Set()方法后,其他调用WaitOne的线程获得信号得以继续执行,而ManualResetEvent不会自动将信号置为不发送。也就是说,除非手工调用了ManualResetEvent.Reset()方法,则ManualResetEvent将一直保持有信号状态,ManualResetEvent也就可以同时唤醒多个线程继续执行。

在多线程的代码里,可以使用一个ManualResetEvent对象来控制线程所有线程;只要在调用WaitOne()方法前,调用Reset()方法,因为WaitOne()控制的是当前线程;但是这样做,ManualResetEvent对象的管理逻辑会变得复杂;所以这里建议一条线程一个ManualResetEvent对象。

 

namespace ResetEventTest
{
    class Program
    {
        private static ManualResetEvent evt = new ManualResetEvent(true);

 

        static void Main(string[] args)
        {
            Boy sender = new Boy(evt);
            Thread th = new Thread(new ThreadStart(sender.SendFlower));
            th.Start();
            Console.WriteLine("送花途中,我等待");
            evt.Reset();
            evt.WaitOne();      //等待工作,阻塞线程
            Console.WriteLine("收到了吧,是我送的");
            Console.ReadLine();
        }
    }

 

    public class Boy
    {
        ManualResetEvent evt;

 

        public Boy(ManualResetEvent _evt)
        {
            evt = _evt;
        }

 

        public void SendFlower()
        {
            Console.WriteLine("正在送花途中");
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(500);
                Console.Write(".");
            }
            Console.WriteLine("\r\n花已经送到MM手中^_^");
            evt.Set();  //通知阻塞程序
        }
    }
}

========================================================

namespace TestMoreResetEvent
{
    class Program
    {
        static void Main(string[] args)
        {
            EventWaitTest zhangsan = new EventWaitTest("张三");
            EventWaitTest lisi = new EventWaitTest("李四");

            Thread t1 = new Thread(new ThreadStart(zhangsan.Consume));
            Thread t2 = new Thread(new ThreadStart(lisi.Consume));
            Thread t3 = new Thread(new ThreadStart(EventWaitTest.Product));

            t1.Start();
            t2.Start();
            t3.Start();

            Console.Read();
        }
    }

    public class EventWaitTest
    {
        private string name; //顾客姓名  
        //private static AutoResetEvent eventWait = new AutoResetEvent(false);  
        private static ManualResetEvent eventWait = new ManualResetEvent(false);
        private static ManualResetEvent eventOver = new ManualResetEvent(false);

        public EventWaitTest(string name)
        {
            this.name = name;
        }

        public static void Product()
        {
            Console.WriteLine("服务员:厨师在做菜呢,两位稍等");
            Thread.Sleep(2000);
            Console.WriteLine("服务员:宫爆鸡丁好了");
            eventWait.Set();
            while (true)
            {
                if (eventOver.WaitOne(1000, false))
                {
                    Console.WriteLine("服务员:两位请买单");
                    eventOver.Reset();
                }
            }
        }

        public void Consume()
        {
            while (true)
            {
                if (eventWait.WaitOne(1000, false))
                {
                    Console.WriteLine(this.name + ":开始吃宫爆鸡丁");
                    Thread.Sleep(2000);
                    Console.WriteLine(this.name + ":宫爆鸡丁吃光了");
                    eventWait.Reset();
                    eventOver.Set();
                    break;
                }
                else
                {
                    Console.WriteLine(this.name + ":等着上菜无聊先玩会手机游戏");
                }
            }
        }
    } 
}

 ===============================================================

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static ManualResetEvent auto = new ManualResetEvent(false);

        static void Main(string[] args)
        {
            Thread t = new Thread(WaitFoSingalToWrite);
            t.Start();
            Thread t1 = new Thread(WaitFoSingalToPlay);
            t1.Start();
            Thread.Sleep(2000);
            auto.Set();
            Console.WriteLine("Main End...");
            Console.ReadLine();
        }

        static void WaitFoSingalToWrite()
        {
            Console.WriteLine("do in...");
            auto.WaitOne();
            Console.WriteLine("do sth..." + DateTime.Now);
            auto.WaitOne(3000, true);
            Console.WriteLine("do sth 1..." + DateTime.Now);
            Console.WriteLine("do out...");
        }

        static void WaitFoSingalToPlay()
        {
            Console.WriteLine("Play in...");
            auto.WaitOne();
            Console.WriteLine("Play sth..." + DateTime.Now);
            auto.WaitOne(3000, true);
            Console.WriteLine("Play sth 1..." + DateTime.Now);
            Console.WriteLine("Play out...");
        }
    }
}