使用线程以及对信号量 AutoResetEvent和ManualResetEvent的理解

2023-10-27

//声明线程  DoThreads是串口执行的方法名称
        Thread    _DoThreads = new Thread(new ThreadStart(DoThreads));
            _DoThreads.IsBackground = true; //是否跟着主线程结束而结束
            _DoThreads.Start(); //打开线程


//在使用完线程后,使用这个方法关闭有线程,也可以自己单个关闭
            System.Environment.Exit(0);




  //使用线程打开方法,会自动关闭
            Task.Factory.StartNew(() =>
            {
                start(_JieBoTaiPort);//方法名
            });

上面是使用和声明线程的方法,但是在线程使用过程中还会有一个问题,就是两个线程,如果线程A改了公共变量C ,线程B想用线程A改过的C

,但是在线程运转中线程A和B,是同时运行的,所以还是会有情况下B获取不到A改的值的,

所以就需要用到信号量了,先把线程B阻塞,如果C被改了,给个状态让他线程继续通行

一、作用

 

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

 

这三个方法的官方定义并不好理解,什么终止、非终止,乱七八糟的。在这里,我们以一种通俗易懂的概念来说明。

 

 

二、比喻

 

如果把每个线程比作一辆汽车的话,AutoResetEventManualResetEvent就是公路上的收费站。

 

其中:

 

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

 

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

 

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

  

 

三、AutoResetEvent和ManualResetEvent的区别

 

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

 

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

 

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

 

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

 

 

所以WaitOne收费操作取决于车闸是否关闭(Reset),如果车闸是开启的,WaitOne的收费愿望只能落空,收费站形同虚设。

 

 

 

四、AutoResetEvent和ManualResetEvent的初始状态

 

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

 

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

 

此版本讲解仅供参考!

这些也算是简单幽默的精讲非常适合小白去理解学习

本文摘自https://blog.csdn.net/snlei/article/details/77651382

感谢此博主那么费工夫的为大家提供那么简单易懂的示例

 

转载于:https://www.cnblogs.com/wangshaod/p/11463585.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用线程以及对信号量 AutoResetEvent和ManualResetEvent的理解 的相关文章

随机推荐

  • vue + element实现el-date-picker的时间格式转换,以及自定义时间格式,修改输入的时间格式

    使用vue2 elementUi实现日期选择输入框的时间格式转换 根据数据的情况自动化格式为需要的格式 如果只是需要修改传给后端的值或者格式 可以使用 value format实现 可以在文档上查看详细的介绍
  • 强化学习——动态规划法

    文章目录 前言 一 动态规划法简单认识 1 基本概念 2 适用情况 3 求解步骤 4 典型案例 二 值函数 1 累计折扣奖励 2 状态值函数 3 动作值函数 4 状态值函数与动作值函数的关系 5 贝尔曼方程 动态规划法核心 三 策略评估 1
  • 学生信息管理系统测试总报告

    目录 1 前言 4 1 1 编写目的 4 1 2 背景说明 4 1 3 适用范围 4 1 4 参考资料 4 2 实验设备与软件环境 4 3 测试需求 5 3 1 需求分析 5 3 2 功能需求 5 3 2 1 系统管理模块 6 3 2 2
  • npm 常见命令 安装 卸载 查看版本

    npm 常见命令 安装 卸载 查看版本 npm list 查看本地已安装模块清单 npm list packageName 查看本地已安装模块版本 npm info packageName 查看模块的详细信息 包括各版本号等 npm vie
  • kcf跟踪算法实例整理

    http blog csdn NET shenxiaolu1984 article details 50905283 本文的跟踪方法效果甚好 速度奇高 思想和实现均十分简洁 其中利用循环矩阵进行快速计算的方法尤其值得学习 另外 作者在主页上
  • C++ 多态的定义及实现

    C 多态的定义及实现 1 多态定义的构成条件 多态是在不同继承关系的类对象 去调同一函数 产生了不同的行为 就是说 有一对继承关系的两个类 这两个类里面都有一个函数且名字 参数 返回值均相同 然后我们通过调用函数来实现不同类对象完成不同的事
  • 通过修改注册表设置代理

    reg add HKCU Software Microsoft Windows CurrentVersion Internet Settings v ProxyEnable t REG DWORD d 1 f 作用 使用自动配置脚本 reg
  • android logcat抓取app日志的方法

    一 logcat抓log方法 adb logcat命令 可以加条件过滤 1 安装SDK 参考android sdk环境安装 2 使用数据线链接手机 在手机助手的sdcard中建立一个1 log的文件或在抓日志时直接导出到电脑位置 3 程序运
  • 笔记本设置扩展屏幕时第二块屏幕的纵横比不对(字体变宽)

    1 在设置中设置扩展 分辨率和缩放按照推荐设置 2 在扩展显示器的高级设置中将屏幕的刷新率设置的比主屏幕低一点即可
  • 安装 Anaconda3 的那些坑

    Anaconda 官网 腿短的人进不去 有梯子的 自行 下载 然后 又翻到 https www anaconda com download windows 看着貌似 挺好 能打开 能下载 能卖萌 又怕国外的站点 下载太慢看到了 清华大学开源
  • IDEA从C盘搬到D盘打开找不到jvm解决办法

    首先 关闭IDEA 将IDEA整个文件夹首先将IDEA整个文件夹复制到你想要放得盘符 打开IDEA安装目录的bin目录 修改idea exe vmoptions中 javaagent D IDEA IntelliJ IDEA 2017 3
  • 认识计算机选题背景,与计算机专业相关的论文_计算机专业的毕业论文题目有哪些_大一我对计算机的认识3000字论文...

    求个金融学和计算机科学与技术这两个专业相关的论文题目 展开全部 互联网金融对传统银行业的影响分析与研究 或者针对某一个细分 比如P2P 支付宝 蚂蚁金融等等 为什么身边的人都想学计算机 计算机真的有那么好吗 作为资深码农 个人觉得这个问题可
  • 最大不能组合数和不能组合数的个数

    A New Change Problem Time Limit 5000 1000 MS Java Others Memory Limit 32768 32768 K Java Others Total Submission s 1609
  • Lua脚本做游戏外挂

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 第一件事当然就是搞账号 淘宝某店 一元100个网易邮箱 店铺已打马赛克 支付后老板给我发了一堆账号 粘贴word文档看下对不对数 刚好100个 不然就差评了 如果这100个
  • 最适合初学者的Python入门详细攻略,一文讲清,赶紧收藏

    目前python可以说是一门非常火爆的编程语言 应用范围也非常的广泛 工资也挺高 未来发展也极好 Python究竟应该怎么学呢 我自己最初也是从零基础开始学习Python的 给大家分享Python的学习思路和方法 一味的买书看书 看视频 是
  • 材料阅读 - 物联网设备指纹 - 某篇论文的相关工作

    20201030 本篇论文 1 是在了解设备指纹的时候看到的 一开始没仔细看 这两天正好集中整理一下 但是这篇文章说实话 不敢苟同 我仔细读了读就感觉有很大问题 看不到具体的干货 文章地址是 1 看了一下他这里的一个同行评议 无话可说 我在
  • jQuery 判断数组集合 是否包含相同元素.

    定义 组装数组对象 筛选重复对象 isRepeat function data var i 0 var obj var arry for i i lt data length i obj data i if
  • 强化学习 学习资料整理(持续更新)

    关于强化学习 比较经典的书当然是 Richard Sutton 的 Reinforcement Learning An Introduction 下面的资料大部分也是关于这本书的读书笔记和相关课程及代码 教学视频系列 强化学习纲要 十课 代
  • 2028:【例4.14】百钱买百鸡

    2028 例4 14 百钱买百鸡 时间限制 1000 ms 内存限制 65536 KB 提交数 1393 通过数 595 题目描述 百钱买百鸡问题 鸡翁一 值钱五 鸡母一 值钱三 鸡雏三 值钱一 百钱买百鸡 问鸡翁 鸡母 鸡雏各几何 输入
  • 使用线程以及对信号量 AutoResetEvent和ManualResetEvent的理解

    声明线程 DoThreads是串口执行的方法名称 Thread DoThreads new Thread new ThreadStart DoThreads DoThreads IsBackground true 是否跟着主线程结束而结束