1、C#ManualResetEvent和AutoResetEvent使用笔记

一、两者区别

1.ManualResetEvent 调用一次Set()后将允许恢复所有被阻塞线程。需手动在调用WaitOne()之后调用Reset()重置信号量状态为非终止,然后再次调用WaitOne()的时候才能继续阻塞线程,反之则不阻塞

2.AutoResetEvent,调用一次Set()只能继续被阻塞的一个线程,多次调用Set()才行,但不需手动调用Reset();再次调用WaitOne()的时候又能阻塞线程,也是和前者的区别

3.两者单个实例均可阻塞一个或多个线程,在多个线程中调用 主线程 创建的 两者单个实例.WaitOne(),前提是两者实例必须是非终止状态

4.两者实例化构造参数解释

public AutoResetEvent(bool initialState);

true:设置终止状态。相当于调用了Set(),即首次不会被WaitOne()阻塞,下次执行WaitOne()才会被阻塞

false:设置非终止状态。遇到WaitOne()立即阻塞所在的一个或多个线程

  1. 两者都只会阻塞WaitOne()所在的线程,WaitOne()可被多个线程调用

二、在哪里创建信号量实例?

一般情况下在工作线程中创建信号量的实例,在其他线程中使用,然后再在工作线程中调用Set(),可以是在非主线程创建实例

三、代码示例

public class Program

{

  //1.AutoResetEvent,调用一次Set()只能继续一个阻塞线程//2.AutoResetEvent调用Set()后自动Reset()static void Main(string[] args){Thread t = null;AutoResetEvent Event = new AutoResetEvent(false);for (int i = 0; i < 2; i++){t = new Thread(() =>{while (true){//阻塞当前线程Event.WaitOne();Console.WriteLine("我是线程:" + Thread.CurrentThread.Name);Thread.Sleep(1000);}});t.Name = i + "";t.Start();}//5秒后允许一个等待的线程继续。当前允许的是线程1Thread.Sleep(5000);Event.Set();//5秒后允许一个等待的线程继续。当前允许的是线程2Thread.Sleep(5000);Event.Set();//PS:如果使用AutoResetEvent的WaitOne()将5个线程阻塞,则需要调用5次Set()才能恢复5;如果再次阻塞时,不需要手动调用Reset();Console.ReadLine();}//1.ManualResetEvent,调用一次Set()允许继续全部阻塞线程,这是和AutoResetEvent的区别//2.ManualResetEvent调用Set()后需要手动Reset(),将信号 设置为非终止状态,只有非终止状态线程中调用WaitOne()才能导所在的致线程阻止。static void Main2(string[] args){Thread t = null;//初始化非终止状态,WaitOne()可以直接阻塞所在的线程ManualResetEvent Event = new ManualResetEvent(false);for (int i = 0; i < 2; i++){t = new Thread(() =>{while (true){//阻塞当前线程Event.WaitOne();Console.WriteLine("我是线程:" + Thread.CurrentThread.Name);Event.ReSet();Thread.Sleep(1000);}});t.Name = i + "";t.Start();}//5秒后允许所有阻塞的线程继续。Thread.Sleep(5000);Event.Set();//PS:如果使用ManualResetEvent将5个线程阻塞,则需要调用1次Set(),将允许所有阻塞的线程继续执行;如果再次阻塞时,则需要手动调用Reset();Console.ReadLine();}

}

原文链接:http://blog.sina.com.cn/s/blog_6f19490b0102x4c4.html

2、ManualResetEvent的理解和使用:

class Program{static void Main(string[] args){//注意:ManualResetEvent可以对所有进行等待的线程进行统一控制//true-初始状态为发出信号;false-初始状态为未发出信号ManualResetEvent mre = new ManualResetEvent(false);//线程池开启10个线程for (int i = 0; i < 10; i++){int k = i;ThreadPool.QueueUserWorkItem(t =>{Console.WriteLine($"这是第{k+1}个线程,线程ID为{Thread.CurrentThread.ManagedThreadId}");//等待信号,没有信号的话不会执行后面的语句,因为初始状态是false,所以后面的语句暂时不会执行mre.WaitOne();Console.WriteLine($"第{k+1}个线程获得信号,线程ID为{Thread.CurrentThread.ManagedThreadId}");});}Thread.Sleep(5000);Console.WriteLine("\r\n 5秒后发出信号... \r\n");//Set()方法:释放信号,所有等待信号的线程都将获得信号,开始执行WaitOne()后面的语句mre.Set();Console.ReadKey();}}

执行结果如图:

可见,没有信号时,WaitOne()后面的语句都不执行(被阻塞),当Set()释放信号后,所有阻塞的线程都开始继续执行。
原文链接:https://blog.csdn.net/u013986317/article/details/87909603

原文:http://www.cnblogs.com/li-peng/p/3291306.html

3、详解 ManualResetEvent(转):

今天详细说一下ManualResetEvent

它可以通知一个或多个正在等待的线程已发生事件,允许线程通过发信号互相通信,来控制线程是否可心访问资源

当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 ManualResetEvent 置于非终止状态。此线程可被视为控制 ManualResetEvent。调用 ManualResetEvent 上的WaitOne 的线程将阻止,并等待信号。当控制线程完成活动时,它调用 Set 以发出等待线程可以继续进行的信号。并释放所有等待线程。

一旦它被终止,ManualResetEvent 将保持终止状态,直到它被手动重置。即对 WaitOne 的调用将立即返回。

上面是它的功能描述,你可能会有点晕。我会用代码一点一点解释它,看完我写的这些内容,你自己运行一下代码你就会明白它的功能

源代码:ManualResetEventDemo.rar

我们从初始化来开始讲

可以通过将布尔值传递给构造函数来控制 ManualResetEvent 的初始状态,如果初始状态处于终止状态,为 true;否则为 false。

我用代码 让大家看一下什么是终止状态和非终止状态

先看一下代码

class Program{static ManualResetEvent _mre = new ManualResetEvent(false);static void Main(string[] args){Thread[] _threads = new Thread[3];for (int i = 0; i < _threads.Count(); i++){_threads[i] = new Thread(ThreadRun);_threads[i].Start();}}static void ThreadRun(){int _threadID = 0;while (true){_mre.WaitOne();_threadID = Thread.CurrentThread.ManagedThreadId;Console.WriteLine("current Tread is " + _threadID);Thread.Sleep(TimeSpan.FromSeconds(2));}}}

当初始化为true时,为终止状态

static ManualResetEvent _mre = new ManualResetEvent(true);

执行结果

当初始化为false时,为非终止状态

static ManualResetEvent _mre = new ManualResetEvent(false);
执行结果为

这样我们就能看出来

终止状态时WaitOne()允许线程访问下边的语句

非终止状态时WaitOne()阻塞线程,不允许线程访问下边的语句

我们也可以把WaitOne()放在方法最下边

static void ThreadRun(){int _threadID = 0;while (true){_threadID = Thread.CurrentThread.ManagedThreadId;Console.WriteLine("current Tread is " + _threadID);Thread.Sleep(TimeSpan.FromSeconds(2));_mre.WaitOne();}}

当初始化为true时执行结果和上边的一样会不停的执行

初始化为false时执行到waitOne()时就阻塞线程不会再往下执行了

接下来你可能就会想当在非终止状态时怎么让线程继续执行,怎么再让它停下来,这就要用了set()和Reset()方法了

把非终止状态改为终止状态用Set()方法

把终止状态改为非终止状态用Reset()方法

我用用代码来实现它们只要把我们上 边的代码做一下改动

class Program{static ManualResetEvent _mre = new ManualResetEvent(false);static void Main(string[] args){Console.WriteLine("输入1为Set()   开始运行");Console.WriteLine("输入2为Reset() 暂停运行");Thread[] _threads = new Thread[3];for (int i = 0; i < _threads.Count(); i++){_threads[i] = new Thread(ThreadRun);_threads[i].Start();}while (true){switch (Console.ReadLine()){case "1":_mre.Set();Console.WriteLine("开始运行");break;case "2":_mre.Reset();Console.WriteLine("暂停运行");break;default:break;}}}static void ThreadRun(){int _threadID = 0;while (true){_threadID = Thread.CurrentThread.ManagedThreadId;Console.WriteLine("current Tread is " + _threadID);Thread.Sleep(TimeSpan.FromSeconds(2));_mre.WaitOne();}}}

当输入1 时会调用 Set()方法 ManualResetEvent 处于终止状态会WaitOne不会阻塞线程会一直运行下去

当输入2时会调用 Reser()方法ManualResetEvent处于非终止状态WaitOne会阻塞线程直到再调用 Set()方法

看一下执行结果吧

代码:ManualResetEventDemo.rar
https://files-cdn.cnblogs.com/files/li-peng/ManualResetEventDemo.rar

4、ManualResetEvent用法

   http://blog.tom.com/blog/read.php?bloggerid=313638&blogid=13505

Thread and Sync In C# (C#中的线程与同步)
别相信别人告诉你的所有的事。其实C#中的线程是很简单的。
线程是程序中的控制流程的封装。你可能已经习惯于写单线程程序,也就是,程序在它们的代码中一次只在一条路中执行。如果你多弄几个线程的话,代码运行可能会更加“同步”。在一个有着多线程的典型进程中,零个或更多线程在同时运行。但是,在有着N个CPU的机器上,一个线程只能在给定的时间上在一个CPU上运行,因为每个线程都是一个代码段,每个CPU一次只能运行一段代码。而看起来像是N个同时完成是线程间共享CPU时间片的效果。这个例子里,我们将创建另一个线程,我们将用两个线程演示多线程的工作方式,最后,我们实现两个线程(主线程与新线程)同步,在新线程工作前必须等待消息。建立线程前我们必须引入System.Threading命名空间。然后我需要知道的是,线程得为控制流程建立一个起点。起点是一个函数,可以使一个相同的调用或其它。
这里你可以看到在同一个类中定义的起点函数。

using System;
using  System.Threading;
namespace  ThreadingTester
{ThreadClass{public static void trmain()for(int x=0;x < 10;x++){Thread.Sleep(1000);Console.WriteLine(x);}}  static void Main(string[] args){Thread thrd1=new Thread(new ThreadStart(trmain));thrd1.Start();for(int x=0;x < 10;x++) {Thread.Sleep(900);Console.WriteLine("Main    :" + x);}}}
}

Thread.Sleep(n)方法把“this”线程置于n毫秒的休眠状态。你可以看看这个例子,在主函数我们定义了一个新的线程,其中它的起点是函数trmain(),我们然后包含了Start()方法开始执行。如果你运行这个例子,你就会了解线程间的切换(让CPU从运行一个线程转到另一个线程)让线程几乎同时运行,为了能看哪个线程运行更快我把主线程设置比新线程少100毫秒。
现在,在开始线程前,先给线程命名:

Thread thrd1=new Thread(new ThreadStart(trmain));thrd1.Name="thread1";thrd1.Start();Thread tr = Thread.CurrentThread;Console.WriteLine(tr.Name);

在完成上面程序后,设想我们不想在一开始新线程就让它马上运行结束,也就是说,我们开启了一个新线程,让它运行,在某个特定的时间点,新线程暂停并等待从主线程(或其他线程)发来的消息。
我们可以这样定义:

  public static ManualResetEvent mre = new ManualResetEvent(false);

ManualResetEvent建立时是把false作为start的初始状态,这个类用于通知另一个线程,让它等待一个或多个线程。注意,为了通知或监听同一个线程,所有的其它线程都能访问那个类。
等待线程这样写:

  mre.WaitOne();

这将引起等待线程无限期的阻塞并等待类来通知。
发信号的线程应该这样:

mre.Set();

这样类就会被通知,值变成true,等待线程就会停止等待。在通知事件发生后,我们就可以使用下面语句把线程置于基状态:

  mre.Reset();

现在让我们在程序执行一下:

using  System;
using  System.Threading;namespace  ThreadingTester
{ThreadClass{public static ManualResetEvent mre=new ManualResetEvent(false);public static void trmain(){Thread tr = Thread.CurrentThread;Console.WriteLine("thread: waiting for an event");mre.WaitOne();Console.WriteLine("thread: got an event");for(int x=0;x < 10;x++){Thread.Sleep(1000);Console.WriteLine(tr.Name +": " + x);}}  static void Main(string[] args){Thread thrd1=new Thread(new ThreadStart(trmain));thrd1.Name="thread1";thrd1.Start();for(int x=0;x < 10;x++) {Thread.Sleep(900);Console.WriteLine("Main:" + x);if(5==x)mre.Set();}while(thrd1.IsAlive){Thread.Sleep(1000);Console.WriteLine("Main: waiting for thread to stopdot.gif");}}}
}

两者都继承自EventWaitHandle,自然也就有点相通的地方了

简单来说,无论是AutoResetEvent还是ManualResetEvent,都是通过发出Signal信号来通知正在等待的线程的。有人可能要问,为什么要用它们来做这些事情, 嗯, 是这样的, 在.Net的多线程环境中,资源的共享变得尤其重要,如果没有一个有效的方法来维护资源的原子状态,在抢占式的CPU环境中,所有的事情都会变得无法控制。AutoResetEvent和ManualResetEvent正是用来保证资源的原子性的一个手段的两个方面。正如它们的名字一样, AutoResetEvent会在每次被Signal了之后自动(Automatically)转变为UnSignal,而ManualResetEvent则不然,无论是Signal还是UnSignal都需要人为的介入去改变它的状态。

在AutoResetEvent的构造函数中,有唯一的一个参数,initialState,Boolean类型,它用来初始化AutoResetEvent的Signal状态,True为Signal,False为UnSignal,这与ManualResetEvent的构造函数是一样的。

AutoResetEvent或ManualResetEvent都是通过Set()/Reset()两个方法来Signal/UnSignal信号,通过调用WaitOne方法来阻塞当前线程,当收到Signal后就继续往下执行。上面提到过,AutoResetEvent会自动把信号复位(自动调用Reset),而ManualResetEvent则需要人手复位,也就是说,AutoResetEvent每次只允许一条线程进入,其它所有需要访问该资源的线程都要排队等候,直到AutoResetEvent得到信号后,下一条线程开始工作,同时AutoResetEvent又会自动复位信号,让其他线程继续等候;而ManualResetEvent则每次可以唤醒多个线程,因为当ManualResetEvent得到信号后,其他调用WaitOne方法的线程都将得到信号得以继续往下执行,ManualResetEvent不会自动复位信号,换句话说,除非手动的调用了ManualResetEvent.Reset方法,否则ManualResetEvent一直保持有信号状态,这样就可以同时唤醒多条线程了

作为一个示例,下面的DemoCode一开始就运行一条子线程,然后用AutoResetEvent/ManualResetEvent来控制MessageBox的输出流程。

如果在Foo和button1_Click里面用AutoResetEvent,一开始得到"1",然后每点击一次Button1得到"2"和"3"。

如果用ManualResetEvent,一开始得到"1",然后只需点击Button1一次,就可以得到"2"和"3"了

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

C#学习(二十八)——ManualResetEvent的理解和使用相关推荐

  1. Linux操作系统学习笔记(二十八)深入理解CPU

    一. 前言   在前面一些文章中多多少少有提到一些CPU的结构以及对应的寄存器等,但是总觉得不够透彻,所以单开一文详细叙述CPU的各种知识,从而加深对操作系统和性能的理解.本文从最基本的加法器和乘法器 ...

  2. Java多线程学习二十八:原子类和 volatile 有什么异同?

    原子类和 volatile 有什么异同 案例说明 volatile 和原子类的异同 我们首先看一个案例.如图所示,我们有两个线程. 在图中左上角可以看出,有一个公共的 boolean flag 标记位 ...

  3. cocos2d-x的初步学习二十八之爱消除一

    这篇文章中,我们将模仿某个游戏来实现,首页我们做首界面,这里都是一些UI元素的布局,其中会涉及到一些动画,比如贝塞尔曲线,还有cctableview来显示我们的得分,做个排行榜,OK,下面我直接上代码 ...

  4. ballerina 学习二十八 快速grpc 服务开发

    ballerina 的grpc 开发模型,对于开发者来说简单了好多,不是schema first 的方式,而是我们 只要编写简单的ballerina service 就可以了,proto 文件是自动帮 ...

  5. Java小白学习二十八——冒泡排序

    冒泡排序 比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置 每一次比较,都会产生一个最大,或者最小的数字 下一轮则可以少一次排序 依次循环,直到结束 package com. ...

  6. OpenCV学习笔记(二十六)——小试SVM算法ml OpenCV学习笔记(二十七)——基于级联分类器的目标检测objdect OpenCV学习笔记(二十八)——光流法对运动目标跟踪Video Ope

    OpenCV学习笔记(二十六)--小试SVM算法ml 总感觉自己停留在码农的初级阶段,要想更上一层,就得静下心来,好好研究一下算法的东西.OpenCV作为一个计算机视觉的开源库,肯定不会只停留在数字图 ...

  7. 深度学习之图像分类(二十八)-- Sparse-MLP(MoE)网络详解

    深度学习之图像分类(二十八)Sparse-MLP(MoE)网络详解 目录 深度学习之图像分类(二十八)Sparse-MLP(MoE)网络详解 1. 前言 2. Mixture of Experts 2 ...

  8. 【Vue学习】—Vue UI组件库(二十八)

    [Vue学习]-Vue UI组件库(二十八) 一.移动端常用的UI组件库 二.PC端常用的UI组件库 三.具体使用自行查看文档,这里就不做概述了

  9. JavaScript学习(二十八)—事件冒泡和事件捕获

    JavaScript学习(二十八)-事件冒泡和事件捕获 一.什么是事件流? 简单说,事件流就是指事件的执行顺序,他包含两种模式:事件冒泡.事件捕获. (一).事件冒泡 最常用的一种模式,就是指事件的执 ...

  10. 嵌入式系统设计师学习笔记二十八:嵌入式程序设计③——高级程序设计语言

    嵌入式系统设计师学习笔记二十八:嵌入式程序设计③--高级程序设计语言 解释程序和编译程序 编译器的工作阶段示意图 语法错误:非法字符,关键字或标识符拼写错误 语法错误:语法结构出错,if--endif ...

最新文章

  1. linux sheel script demo
  2. [转]Ubantu vmware tools 安装
  3. node项目架构与优化
  4. Linux下编写选择排序(C语言)
  5. SQL SERVER数据库多条件查询
  6. 快手春晚10亿元红包玩法来了:最高得2020元现金
  7. 60-30-012-使用-Kafka不停机删除topic数据(自动建立topic)md
  8. 【转载】C++ ,C#数据类型对照
  9. c语言右上左下遍历数组,如何将一个数组的元素循环左移?
  10. kettle spoon判断增量更新_【论文推荐】张斌等:基于改进 SOINN 算法的恶意软件增量检测方法...
  11. 常州儿童计算机培训,常州推荐儿童编程培训班哪几家靠谱
  12. 关于matlab中 CC = bwconncomp(A,4)命令的问题
  13. 如何自定义设置Mac OS系统和windows系统键盘的方法
  14. PHP RSA2 签名算法
  15. npm安装依赖包 版本冲突怎么办 --legacy-peer-deps的正确使用方
  16. 别乱说,算法才不是脑筋急转弯
  17. Android计算器LinearLayout实现布局
  18. html页面中的快捷键设置
  19. SparkSteaming使用
  20. java计算机毕业设计学生宿舍信息管理源程序+mysql+系统+lw文档+远程调试

热门文章

  1. 数据仓库中的慢变化维度和快变化维度
  2. 企业管理系统有几种类型,分别是什么?
  3. 智慧职教云答案在哪里找_云课堂智慧职教答案哪里找?
  4. 2020年中国高精度卫星导航定位行业现状、竞争格局及发展前景分析,基于北斗系统全面建成,定位技术向多场景发展「图」
  5. ZXing条码扫描----竖屏解决方案
  6. 付费应用程序协议下载 苹果_苹果商店 付费app协议填写 apple苹果IOS内购申请教程协议、税务和银行业务配置...
  7. javascript模块化编程规范
  8. ThinkPHP学生社团管理系统
  9. 农村常见60种野生中草药
  10. 星空特效HTML代码,旋转的星空特效代码