AutoResetEvent和ManualResetEvent(多线程操作)
摘自风中灵药的博客:https://www.cnblogs.com/qingyun163/archive/2013/01/05/2846633.html#!comments
AutoResetEvent和ManualResetEvent可用于控制线程暂停或继续,拥有重要的三个方法:WaitOne、Set和Reset。
如果把每个线程比作一辆汽车的话,AutoResetEvent和ManualResetEvent就是公路上的收费站。
其中:
Reset 关闭收费站车闸禁止通行(拦截车辆才好收费啊);
WaitOne 收费员等待下一辆车辆过来(然后收费);
Set 开启收费站车闸放行(交钱了就让过去)。
AutoResetEvent和ManualResetEvent的区别
既然AutoResetEvent和ManualResetEvent都是收费站,那么它们之间有什么不同之处吗?
顾名思义,Auto即自动,Manual即手动,而Reset根据上面的比喻表示关闭车闸,也就是前者可自动关闭车闸,后者需手动关闭车闸。
自动关闭车闸:即一辆车交钱通过后,车闸会自动关闭,然后再等待下一辆车过来交费。即每辆车都要经过这么几个步骤:被阻 > 交费 > 通行 > 车闸关闭
手动关闭车闸:车闸打开后,车闸不会自动关闭,如果不手动关闭车闸(即调用ManualResetEvent.Reset()方法)的话,车辆会一辆接一辆地通过……
AutoResetEvent和ManualResetEvent的初始状态
通过设置AutoResetEvent和ManualResetEvent构造函数可初始化收费站车闸状态:
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, , );//2秒后关闭车闸
Console.ReadKey();
}
static void Car1()
{
_tollStation.WaitOne();//等待开启车闸,即_tollStation.Set();
Console.WriteLine("车辆1,顺利通过。");
}
static void Car2()
{
Thread.Sleep();//睡眠3秒
_tollStation.WaitOne();//当醒来后车闸已经被关闭
Console.WriteLine("车辆2,顺利通过。");//所以车辆2不会被通过
}
/// <summary>
/// 2秒后关闭车闸
/// </summary>
static void CloseDoor(object o)
{
_tollStation.Reset();//关闭车闸
}
运行将打印:
车辆1,顺利通过。
而车辆2将不会通过,因为当车辆2醒来时,车闸在2秒前已被关闭。
AutoResetEvent和ManualResetEvent(多线程操作)的更多相关文章
- AutoResetEvent 和 ManualResetEvent 多线程应用
AutoResetEvent 1.用于在多线程,对线程进行阻塞放行 static AutoResetEvent auth0 = new AutoResetEvent(false); static Au ...
- 多线程间通信之AutoResetEvent和ManualResetEvent的原理分析和开发示例
AutoResetEvent 允许线程通过发信号互相通信. 通常,当线程需要独占访问资源时使用该类. 线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号. 如果 AutoRe ...
- C#多线程同步事件及等待句柄AutoResetEvent 和 ManualResetEvent
最近捣鼓了一下多线程的同步问题,发现其实C#关于多线程同步事件处理还是很灵活,这里主要写一下,自己测试的一些代码,涉及到了AutoResetEvent 和 ManualResetEvent,当然还有也 ...
- 多线程间通信之AutoResetEvent和ManualResetEvent的原理分析
AutoResetEvent 允许线程通过发信号互相通信. 通常,当线程需要独占访问资源时使用该类. 线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号. 如果 AutoRe ...
- c# 多线程编程中AutoResetEvent和ManualResetEvent
作为等同于Java的wait,notify,notifyAll的存在,AutoResetEvent和ManualResetEvent分别实现了notify和notifyAll的功能,下面的代码简单讲解 ...
- C# 应用 - 多线程 6) 处理同步数据之手动同步 AutoResetEvent 和 ManualResetEvent
1. 类的关系 AutoResetEvent 和 ManualResetEvent 都继承自 System.Threading.EventWaitHandle 类(EventWaitHandle 继承 ...
- C#多线程操作界面控件的解决方案(转)
C#中利用委托实现多线程跨线程操作 - 张小鱼 2010-10-22 08:38 在使用VS2005的时候,如果你从非创建这个控件的线程中访问这个控件或者操作这个控件的话就会抛出这个异常.这是微软为了 ...
- 线程同步(AutoResetEvent与ManualResetEvent)
前言 在我们编写多线程程序时,会遇到这样一个问题:在一个线程处理的过程中,需要等待另一个线程处理的结果才能继续往下执行.比如:有两个线程,一个用来接收Socket数据,另一个用来处理Socket数据, ...
- WaitHandle、AutoResetEvent、ManualResetEvent
多线程中的锁系统(三)-WaitHandle.AutoResetEvent.ManualResetEvent 介绍 本章主要说下基于内核模式构造的线程同步方式,事件,信号量. 目录 一:理论 二:Wa ...
随机推荐
- BZOJ 1006 完美消除序列&最大势算法&弦图
K国是一个热衷三角形的国度,连人的交往也只喜欢三角原则.他们认为三角关系:即AB相互认识,BC相互认识,CA相互认识,是简洁高效的.为了巩固三角关系,K国禁止四边关系,五边关系等等的存在.所谓N边关系 ...
- GIT 工作流程常用用命令大全
一.Git基本工作流程 1.Git工作区域 2.向仓库中添加文件流程 二.Git初始化及仓库创建和操作 1.Git安装之后需要进行一些基本信息设置 a.设置用户名:git config -- g ...
- 批量升级 CentOS bash
#! /usr/bin/env python #coding=utf-8 from fabric.api import * from fabric.state import * env.rol ...
- MySQL_DBA整理
MySQL_DBA整理(转) 2011-01-26 16:51:41 分类: Mysql/postgreSQL 转自:丁丁:http://www.itpub.net/thread-831154-2- ...
- 5 解析器、url路由控制、分页、渲染器和版本
1 数据解析器 1 什么是解析器 相当于request 中content-type 对方传什么类型的数据,我接受什么样的数据:怎样解析 无论前面传的是什么数据,都可以解开 例如:django不能解析j ...
- 【原】eclipse save action设置文件保存时自动格式化
学了一段java了,发现其实eclipse有很多实用小功能,能够让你编码的时候快捷方便,如果你苦于一些你常用到的功能无法自动实现,那么你可以上网查一下,就会发现其实eclipse已经给你提供了便捷之路 ...
- Linux帮助文档
Linux当中有许多命令: 在Linux中提供了详细的帮组文档,利用好可以提高使用效率: 1.help参数 大多数命令都可以使用 -h 或 --help 参数来获取该命令的使用方法.参数等信息: ...
- Windows:打印为PDF(PDF转换器)
造冰箱的大熊猫@cnblogs 2019/4/17 文中图片可通过点击鼠标右键查看大图 Windows下实现PDF打印的几个办法: 1.Foxit Reader(福昕PDF浏览器) 安装Foxit R ...
- Word:高亮显示文档中的所有英文字符
造冰箱的大熊猫,本文适用于Microsoft Office 2007@cnblogs 2019/4/2 文中图片可通过点击鼠标右键查看大图 1.场景 某天在阅读一个中英文混编的Word文档时,希望将 ...
- 51 Nod 1282 时钟 (循环中的最小表示+哈希)
1282 时钟 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 有N个时钟,每个时钟有M个指针,P个刻度.时钟是圆形 ...