个人对AutoResetEvent和ManualResetEvent的理解(转载)
仅个人见解,不对之处请指正,谢谢。
一、作用
AutoResetEvent和ManualResetEvent可用于控制线程暂停或继续,拥有重要的三个方法:WaitOne、Set和Reset。
这三个方法的官方定义并不好理解,什么终止、非终止,乱七八糟的。在这里,我们以一种通俗易懂的概念来说明。
二、比喻
如果把每个线程比作一辆汽车的话,AutoResetEvent和ManualResetEvent就是公路上的收费站。
其中:
Reset 关闭收费站车闸禁止通行(拦截车辆才好收费啊);
WaitOne 收费员等待下一辆车辆过来(然后收费);
Set 开启收费站车闸放行(交钱了就让过去)。
三、AutoResetEvent和ManualResetEvent的区别
既然AutoResetEvent和ManualResetEvent都是收费站,那么它们之间有什么不同之处吗?
顾名思义,Auto即自动,Manual即手动,而Reset根据上面的比喻表示关闭车闸,也就是前者可自动关闭车闸,后者需手动关闭车闸。
自动关闭车闸:即一辆车交钱通过后,车闸会自动关闭,然后再等待下一辆车过来交费。即每辆车都要经过这么几个步骤:被阻 > 交费 > 通行 > 车闸关闭
手动关闭车闸:车闸打开后,车闸不会自动关闭,如果不手动关闭车闸(即调用ManualResetEvent.Reset()方法)的话,车辆会一辆接一辆地通过……
所以WaitOne收费操作取决于车闸是否关闭(Reset),如果车闸是开启的,WaitOne的收费愿望只能落空,收费站形同虚设。
四、AutoResetEvent和ManualResetEvent的初始状态
通过设置AutoResetEvent和ManualResetEvent构造函数可初始化收费站车闸状态:
new Auto/ManualResetEvent(false):车闸默认关闭;
new Auto/ManualResetEvent(true): 车闸默认开启。
如果new Auto/ManualResetEvent(true),即车闸默认开启的话,WaitOne没任何意义,车辆该通过还通过。
看下面代码:
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("噫!车闸是开的,我过来了!");
}
运行将打印:
噫!车闸是开的,我过来了!
如果将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秒前已被关闭。
七、总结
1、看起来,ManualResetEvent更加自由、开放。如果把AutoResetEvent看作是只能单人通过的独木桥的话,那么ManualResetEvent就像一座城门,一下子可以涌入千军万马,当然你也可以随时关闭城门,让后面的人进不来。
2、AutoResetEvent.Set() = ManualResetEvent.Set() + ManualResetEvent.Reset();
3、如果共享资源仅允许一个线程单独使用的情况下,可以选择AutoResetEvent;如果共享资源允许多个线程同时使用,则可以选择ManualResetEvent。
4、如果要控制多个线程暂停、继续,可以选择ManualResetEvent。
5、等您来补充……
原文链接:http://www.cnblogs.com/qingyun163/archive/2013/01/05/2846633.html
个人对AutoResetEvent和ManualResetEvent的理解(转载)的更多相关文章
- 个人对AutoResetEvent和ManualResetEvent的理解
一.作用 AutoResetEvent和ManualResetEvent可用于控制线程暂停或继续,拥有重要的三个方法:WaitOne.Set和Reset. 这三个方法的官方定义并不好理解,什么终止.非 ...
- [转]个人对AutoResetEvent和ManualResetEvent的理解
仅个人见解,不对之处请指正,谢谢. 一.作用 AutoResetEvent和ManualResetEvent可用于控制线程暂停或继续,拥有重要的三个方法:WaitOne.Set和Reset. 这三个方 ...
- AutoResetEvent和ManualResetEvent理解 z
AutoResetEvent和ManualResetEvent用于多线程之间代码执行顺序的控制,它们继承自WaitHandle,API相同,但在使用中还是有区别的. 每次使用时虽然理解了,但由于没有去 ...
- C#理解AutoResetEvent和ManualResetEvent
当在C#使用多线程时就免不了使用AutoResetEvent和ManualResetEvent类,可以理解这两个类可以通过设置信号来让线程停下来或让线程重新启动,其实与操作系统里的信号量很相似(汗,考 ...
- C#深入理解AutoResetEvent和ManualResetEvent
当在C#使用多线程时就免不了使用AutoResetEvent和ManualResetEvent类,可以理解这两个类可以通过设置信号来让线程停下来或让线程重新启动,其实与操作系统里的信号量很相似(汗,考 ...
- AutoResetEvent和ManualResetEvent理解
AutoResetEvent和ManualResetEvent用于多线程之间代码执行顺序的控制,它们继承自WaitHandle,API相同,但在使用中还是有区别的. 每次使用时虽然理解了,但由于没有去 ...
- C#多线程同步事件及等待句柄AutoResetEvent 和 ManualResetEvent
最近捣鼓了一下多线程的同步问题,发现其实C#关于多线程同步事件处理还是很灵活,这里主要写一下,自己测试的一些代码,涉及到了AutoResetEvent 和 ManualResetEvent,当然还有也 ...
- C#AutoResetEvent和ManualResetEvent的区别
一:终止状态和非终止状态 首先说说线程的终止状态和非终止状态.AutoResetEvent和ManualResetEvent的构造函数中,都有bool变量来指明线程的终止状态和非终止状态.true表示 ...
- 线程同步(AutoResetEvent与ManualResetEvent)
前言 在我们编写多线程程序时,会遇到这样一个问题:在一个线程处理的过程中,需要等待另一个线程处理的结果才能继续往下执行.比如:有两个线程,一个用来接收Socket数据,另一个用来处理Socket数据, ...
随机推荐
- webpack练手项目之easySlide(三):commonChunks(转)
Hello,大家好. 在之前两篇文章中: webpack练手项目之easySlide(一):初探webpack webpack练手项目之easySlide(二):代码分割 与大家分享了webpack的 ...
- 20145308刘昊阳 《Java程序设计》第7周学习总结
20145308刘昊阳 <Java程序设计>第7周学习总结 教材学习内容总结 第13章 时间与日期 13.1 认识时间与日期 13.1.1 时间的度量 格林威治时间(GMT) 世界时(UT ...
- ACM 最少步数
最少步数 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 这有一个迷宫,有0~8行和0~8列: 1,1,1,1,1,1,1,1,1 1,0,0,1,0,0,1,0,1 ...
- 转:JavaScript中的this陷阱的最全收集
在其他地方看到的,觉得解释的狠详细,特此分享 当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程.事件驱动.面向对象等一堆词语,但是如果真的让你解释一下这些概念,可能真解释不清 ...
- BZOJ 1083 题解
1083: [SCOI2005]繁忙的都市 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2431 Solved: 1596[Submit][Sta ...
- iOS9 升级XCode7遇到的问题收集
开发环境运行 各位可能会觉得,笔者在此还要讲开发环境的运行,是不是多此一举.其实并非如此,综合笔者这几年iOS开发经验的总结,运行新版本,特别是测试版本的Xcode是一个需要格外小心的事情, ...
- 热烈庆祝华清远见成功自主研发Farsight TV 智能机顶盒
近日,华清远见研发中心再传喜讯:Farsight TV 智能机顶盒研发成功并投入教学!这是华清远见研发中心继开源平板电脑.智能医疗终端.智能家居终端后独立成功研发的又一智能硬件!至此,开创了华清远见自 ...
- 翻译-In-Stream Big Data Processing 流式大数据处理
相当长一段时间以来,大数据社区已经普遍认识到了批量数据处理的不足.很多应用都对实时查询和流式处理产生了迫切需求.最近几年,在这个理念的推动下,催生出了一系列解决方案,Twitter Storm,Yah ...
- C++ string 类的 find 方法实例详解
1.C++ 中 string 类的 find 方法列表 size_type std::basic_string::find(const basic_string &__str, size_ty ...
- GO语言练习:for基本用法
1.代码 2.运行 1.代码 package main import "fmt" func main(){ ; k < ; k++{ JLoop: ; j < ; j+ ...