C#多线程(6):线程通知
C#多线程(6):线程通知
目录
AutoRestEvent 类
常用方法
一个简单的示例
解释一下
复杂一点的示例
解释
回顾一下,前面 lock、Monitor 部分我们学习了线程锁,Mutex 部分学习了进程同步,Semaphor 部分学习了资源池限制。
这一篇将学习 C# 中用于发送线程通知的 AutoRestEvent 类。
AutoRestEvent 类
用于从一个线程向另一个线程发送通知。
微软文档是这样介绍的:表示线程同步事件在一个等待线程释放后收到信号时自动重置。
其构造函数只有一个:
构造函数里面的参数用于设置信号状态。
构造函数 说明
AutoResetEvent(Boolean) 用一个指示是否将初始状态设置为终止的布尔值初始化 AutoResetEvent 类的新实例。
真糟糕的机器翻译。
常用方法
AutoRestEvent 类是干嘛的,构造函数的参数又是干嘛的?不着急,我们来先来看看这个类常用的方法:
方法 说明
Close() 释放由当前 WaitHandle 占用的所有资源。
Reset() 将事件状态设置为非终止,从而导致线程受阻。
Set() 将事件状态设置为有信号,从而允许一个或多个等待线程继续执行。
WaitOne() 阻止当前线程,直到当前 WaitHandle 收到信号。
WaitOne(Int32) 阻止当前线程,直到当前 WaitHandle 收到信号,同时使用 32 位带符号整数指定时间间隔(以毫秒为单位)。
WaitOne(Int32, Boolean) 阻止当前线程,直到当前的 WaitHandle 收到信号为止,同时使用 32 位带符号整数指定时间间隔,并指定是否在等待之前退出同步域。
WaitOne(TimeSpan) 阻止当前线程,直到当前实例收到信号,同时使用 TimeSpan 指定时间间隔。
WaitOne(TimeSpan, Boolean) 阻止当前线程,直到当前实例收到信号为止,同时使用 TimeSpan 指定时间间隔,并指定是否在等待之前退出同步域。
一个简单的示例
这里我们编写一个这样的程序:
创建一个线程,能够执行多个阶段的任务;每完成一个阶段,都需要停下来,等待子线程发生通知,才能继续下一步执行。
.WaitOne() 用来等待另一个线程发送通知;
.Set() 用来对线程发出通知,此时 AutoResetEvent 变成终止状态;
.ReSet() 用来重置 AutoResetEvent 状态;
class Program { // 线程通知 private static AutoResetEvent resetEvent = new AutoResetEvent(false); static void Main(string[] args) { // 创建线程 new Thread(DoOne).Start(); // 用于不断向另一个线程发送信号 while (true) { Console.ReadKey(); resetEvent.Set(); // 发生通知,设置终止状态 } } public static void DoOne() { Console.WriteLine("等待中,请发出信号允许我运行"); // 等待其它线程发送信号 resetEvent.WaitOne(); Console.WriteLine("\n 收到信号,继续执行"); for (int i = 0; i < 5; i++) Thread.Sleep(TimeSpan.FromSeconds(0.5)); resetEvent.Reset(); // 重置为非终止状态 Console.WriteLine("\n第一阶段运行完毕,请继续给予指示"); // 等待其它线程发送信号 resetEvent.WaitOne(); Console.WriteLine("\n 收到信号,继续执行"); for (int i = 0; i < 5; i++) Thread.Sleep(TimeSpan.FromSeconds(0.5)); Console.WriteLine("\n第二阶段运行完毕,线程结束,请手动关闭窗口"); } }
解释一下
AutoResetEvent 对象有终止和非终止状态。Set() 设置终止状态,Reset() 重置非终止状态。
这个终止状态,可以理解成信号已经通知;非终止状态则是信号还没有通知。
注意,注意终止状态和非终止状态指的是 AutoResetEvent 的状态,不是指线程的状态。
线程通过调用 WaitOne() 方法,等待信号;
另一个线程可以调用 Set() 通知 AutoResetEvent 释放等待线程。
然后 AutoResetEvent 变为终止状态。
需要注意的是,如果 AutoResetEvent 已经处于终止状态,那么线程调用 WaitOne() 不会再起作用。除非调用Reset() 。
构造函数中的参数,正是设置这个状态的。true 代表终止状态,false 代表非终止状态。如果使用 new AutoResetEvent(true); ,则线程一开始是无需等待信号的。
在使用完类型后,您应直接或间接释放类型,显式调用 Close()/Dispose() 或 使用 using。 当然,也可以直接退出程序。
需要注意的是,如果多次调用 Set() 的时间间隔过短,如果第一次 Set() 还没有结束(信号发送需要处理时间),那么第二次 Set() 可能无效(不起作用)。
复杂一点的示例
我们设计一个程序:
Two 线程开始处于阻塞状态;
线程 One 可以设置线程 Two 继续运行,然后阻塞自己;
线程 Two 可以设置 One 继续运行,然后阻塞自己;
程序代码如下(运行后,请将键盘设置成英文输入状态再按下按键):
class Program { // 控制第一个线程 // 第一个线程开始时,AutoResetEvent 处于终止状态,无需等待信号 private static AutoResetEvent oneResetEvent = new AutoResetEvent(true); // 控制第二个线程 // 第二个线程开始时,AutoResetEvent 处于非终止状态,需要等待信号 private static AutoResetEvent twoResetEvent = new AutoResetEvent(false); static void Main(string[] args) { new Thread(DoOne).Start(); new Thread(DoTwo).Start(); Console.ReadKey(); } public static void DoOne() { while (true) { Console.WriteLine("\n① 按一下键,我就让DoTwo运行"); Console.ReadKey(); twoResetEvent.Set(); oneResetEvent.Reset(); // 等待 DoTwo() 给我信号 oneResetEvent.WaitOne(); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("\n DoOne() 执行"); Console.ForegroundColor = ConsoleColor.White; } } public static void DoTwo() { while (true) { Thread.Sleep(TimeSpan.FromSeconds(1)); // 等待 DoOne() 给我信号 twoResetEvent.WaitOne(); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("\n DoTwo() 执行"); Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("\n② 按一下键,我就让DoOne运行"); Console.ReadKey(); oneResetEvent.Set(); twoResetEvent.Reset(); } } }
解释
两个线程具有的功能:阻塞自己、解除另一个线程的阻塞。
用电影《最佳拍档》里面的一个画面来理解。
DoOne 、DoTwo 轮流呼吸,不能自己控制自己呼吸,但自己能够决定别人呼吸。
你搞我,我搞你,就能相互呼吸了。
当然WaitOne() 也可以设置等待时间,如果 光头佬(DoOne) 耍赖不让 金刚(DoTwo)呼吸,金刚等待一定时间后,可以强行荡动天平,落地呼吸。
注意,AutoRestEvent 用得不当容易发生死锁。
另外 AutoRestEvent 使用的是内核时间模式,因此等待时间不能太长,不然比较耗费 CPU 时间。
AutoResetEvent 也适合用于线程同步。
另外,线程中使用 WaitOne() ,另一个线程使用 Set() 通知后, AutoResetEvent 对象会自动恢复非终止状态,不需要线程使用 Reset() 。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
阿里云总裁张建锋:企业数字化是一把手工程
“阿里云的愿景就是提供数字经济时代的基础设施。”4月2日,在主题为“企业的数字化未来”的企业家高端对话网络直播公益活动中,阿里云智能总裁张建锋表示。 4月2日,由国务院国资委干部教育培训中心、中国企业联合会主办,中国航天科工集团、海尔、阿里巴巴集团协办的企业家高端对话网络活动成功举办。本次活动聚焦企业数字化未来,对在疫情背景下如何开启数字经济全新的企业范式进行了探讨。 三家数字化标杆企业的负责人隔空连线,共有427万人在线收看了这场直播。 张建锋详解了阿里数字化的关键,并分享了企业数字化的“三步曲”:1,基础设施云化;2,流程与技术同步改造;3,基于数据开展创新和智能化。 附:张建锋演讲核心观点 疫情发生后,利用数字化的平台基础和技术优势,阿里不仅保障了自身的运转,实现十多万员工的云办公、云培训,还向政府、企业和社会输出解决方案,用数字技术
- 下一篇
SAP Commerce Extension Module
Extension modules are structural elements of an extension. 类似ABAP开发包的概念。 An extension may include several extension modules serving as structural elements. Each of them offers a certain set of functionality. The functionality of the extension that you wish to have depends on extension modules that you implement. Extension module分为core和web两类。 core extension module包含这些组件: type system definition 位于items.xml文件里,位置和命名规范: java file extension版本 In addition, every SAP Commerce package contains a file wi...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS6,CentOS7官方镜像安装Oracle11G
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8编译安装MySQL8.0.19
- CentOS6,7,8上安装Nginx,支持https2.0的开启