AutoResetEvent和ManualResetEvent(多线程操做)

摘自风中灵药的博客:https://www.cnblogs.com/qingyun163/archive/2013/01/05/2846633.html#!commentshtml

AutoResetEvent和ManualResetEvent可用于控制线程暂停或继续,拥有重要的三个方法:WaitOneSetReset函数

 

若是把每一个线程比做一辆汽车的话,AutoResetEventManualResetEvent就是公路上的收费站。spa

其中:线程

Reset 关闭收费站车闸禁止通行(拦截车辆才好收费啊);code

WaitOne 收费员等待下一辆车辆过来(而后收费);htm

Set    开启收费站车闸放行(交钱了就让过去)。blog

 

AutoResetEvent和ManualResetEvent的区别队列

既然AutoResetEventManualResetEvent都是收费站,那么它们之间有什么不一样之处吗?get

顾名思义,Auto即自动,Manual即手动,而Reset根据上面的比喻表示关闭车闸,也就是前者可自动关闭车闸,后者需手动关闭车闸。博客

自动关闭车闸:即一辆车交钱经过后,车闸会自动关闭,而后再等待下一辆车过来交费。即每辆车都要通过这么几个步骤:被阻 > 交费 > 通行 > 车闸关闭

手动关闭车闸:车闸打开后,车闸不会自动关闭,若是不手动关闭车闸(即调用ManualResetEvent.Reset()方法)的话,车辆会一辆接一辆地经过……

 

AutoResetEvent和ManualResetEvent的初始状态

经过设置AutoResetEventManualResetEvent构造函数可初始化收费站车闸状态:

new Auto/ManualResetEvent(false)车闸默认关闭;
new Auto/ManualResetEvent(true) 车闸默认开启。

若是new Auto/ManualResetEvent(true),即车闸默认开启的话,是默认让第一辆车经过,而后会拦截下一辆车。

static EventWaitHandle _tollStation = new AutoResetEvent(true);//车闸默认开启

        static void Main(string[] args) { new Thread(Car1).Start(); Console.ReadKey(); } static void Car1() { _tollStation.WaitOne();//因车闸默认开启,WaitOne毫无心义,不会阻止车辆前行
            Console.WriteLine("噫!车闸是开的,我过来了!"); }

此时输出:"噫!车闸是开的,我过来了!"

可是若是改一下

static EventWaitHandle _tollStation = new AutoResetEvent(true);//车闸默认开启

        static void Main(string[] args) { new Thread(Car1).Start(); new Thread(Car1).Start();//执行两次输出的线程 Console.ReadKey(); } static void Car1() { _tollStation.WaitOne();//因车闸默认开启,WaitOne毫无心义,不会阻止车辆前行
            Console.WriteLine("噫!车闸是开的,我过来了!"); }

此时输出:噫!车闸是开的,我过来了!

执行两次线程,可是只会输出一次。由于第二次被阻拦了。

 

若是将new AutoResetEvent(true) 改成new AutoResetEvent(flase),即车闸默认为关闭状态的话,将不会打印任何值,即车辆没法经过。

那如何才能经过呢?必须在主线程中调用Set方法,即打开车闸便可经过。

static EventWaitHandle _tollStation = new AutoResetEvent(false);//车闸默认关闭

        static void Main(string[] args) { new Thread(Car1).Start(); _tollStation.Set();//开启车闸
 Console.ReadKey(); } static void Car1() { _tollStation.WaitOne();//等待开启车闸,即_event.Set();
            Console.WriteLine("车闸开启,我过来了!"); }

运行将打印:

车闸开启,我过来了!

代码很明了,就不解释了,总之就是车闸默认关闭状态下,只有打开车闸(调用Set方法 ),车辆才能通行。

用代码阐释AutoResetEvent的特性

static EventWaitHandle _tollStation = new AutoResetEvent(false);//车闸默认关闭

        static void Main(string[] args) { new Thread(Car1).Start();//车辆1
            new Thread(Car2).Start();//车辆2
 _tollStation.Set(); Console.ReadKey(); } static void Car1() { _tollStation.WaitOne();//等待开启车闸,即_tollStation.Set();
            Console.WriteLine("车辆1,顺利经过。"); } static void Car2() { _tollStation.WaitOne(); Console.WriteLine("车辆2,顺利经过。!"); }

运行将打印:

车辆1,顺利经过。

虽然车辆1和车辆2都在运行,但只有车辆1顺利经过。

由于_tollStation.Set()仅运行了一次,即车辆1经过后车闸被当即关闭,致使车辆2未被经过。

除非,在车辆1经过后再调用一次_tollStation.Set(),即再次打开车闸,车辆2才能经过:

static EventWaitHandle _tollStation = new AutoResetEvent(false);//车闸默认关闭

        static void Main(string[] args) { new Thread(Car1).Start();//车辆1
            new Thread(Car2).Start();//车辆2
            _tollStation.Set();//开启车闸,让车辆1经过
 Console.ReadKey(); } static void Car1() { _tollStation.WaitOne();//等待开启车闸,即_tollStation.Set();
            Console.WriteLine("车辆1,顺利经过。"); _tollStation.Set();//再开启一次车闸,让车辆2经过
 } static void Car2() { _tollStation.WaitOne(); Console.WriteLine("车辆2,顺利经过。"); }

运行将打印:

车辆1,顺利经过。

车辆2,顺利经过。

也就是每调用一次Set,仅有一个线程会继续。换言之,有多少个线程就要调用多少次Set,线程才会所有继续。

这也代表,AutoResetEvent是典型的队列操做形式。

 

用代码阐释ManualResetEvent的特性

在上一个代码块中,_tollStation.Set()调用了两次,两辆车才顺利经过。

那么,有没有什么办法,只调用一次_tollStation.Set()就让两辆或更多辆汽车顺利经过呢?

答案是,将AutoResetEvent改成ManualResetEvent

static EventWaitHandle _tollStation = new ManualResetEvent(false);//改成ManualResetEvent,车闸默认关闭

        static void Main(string[] args) { new Thread(Car1).Start();//车辆1
            new Thread(Car2).Start();//车辆2
            _tollStation.Set();//开启车闸,全部车辆都会经过
 Console.ReadKey(); } static void Car1() { _tollStation.WaitOne();//等待开启车闸,即_tollStation.Set();
            Console.WriteLine("车辆1,顺利经过。"); //_tollStation.Set();//这里再也不须要了
 } static void Car2() { _tollStation.WaitOne(); Console.WriteLine("车辆2,顺利经过。"); }

运行将打印:

车辆1,顺利经过。

车辆2,顺利经过。

这很好的说明了,ManualResetEvent开启车闸后不会自动关闭这一特性。因此调用一次_tollStation.Set(),所有车辆将顺利经过。

若是在某一时刻手动关闭了车闸,则后面的车辆将没法经过。如如下代码:

static EventWaitHandle _tollStation = new ManualResetEvent(false);//改成ManualResetEvent,车闸默认关闭

        static void Main(string[] args) { new Thread(Car1).Start();//车辆1
            new Thread(Car2).Start();//车辆2
 _tollStation.Set();//开启车闸,放行
            Timer timer = new Timer(CloseDoor, null, 0, 2000);//2秒后关闭车闸
 Console.ReadKey(); } static void Car1() { _tollStation.WaitOne();//等待开启车闸,即_tollStation.Set();
            Console.WriteLine("车辆1,顺利经过。"); } static void Car2() { Thread.Sleep(3000);//睡眠3秒
            _tollStation.WaitOne();//当醒来后车闸已经被关闭
            Console.WriteLine("车辆2,顺利经过。");//因此车辆2不会被经过
 } /// <summary>
        /// 2秒后关闭车闸 /// </summary>
        static void CloseDoor(object o) { _tollStation.Reset();//关闭车闸
        }

运行将打印:

车辆1,顺利经过。

而车辆2将不会经过,由于当车辆2醒来时,车闸在2秒前已被关闭。

相关文章
相关标签/搜索