C#多线程(6):线程通知
回顾一下,前面 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 的状态,不是指线程的状态。
另一个线程可以调用 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 使用的是内核时间模式,因此等待时间不能太长,不然比较耗费 CPU 时间。
AutoResetEvent 也适合用于线程同步。
另外,线程中使用 WaitOne() ,另一个线程使用 Set() 通知后, AutoResetEvent 对象会自动恢复非终止状态,不需要线程使用 Reset() 。
C#多线程(6):线程通知的更多相关文章
- C#多线程之线程池篇3
在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...
- C#多线程之线程池篇2
在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...
- C#多线程之线程同步篇3
在上一篇C#多线程之线程同步篇2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier ...
- C#多线程之线程同步篇2
在上一篇C#多线程之线程同步篇1中,我们主要学习了执行基本的原子操作.使用Mutex构造以及SemaphoreSlim构造,在这一篇中我们主要学习如何使用AutoResetEvent构造.Manual ...
- Java多线程 3 线程同步
在之前,已经学习到了线程的创建和状态控制,但是每个线程之间几乎都没有什么太大的联系.可是有的时候,可能存在多个线程多同一个数据进行操作,这样,可能就会引用各种奇怪的问题.现在就来学习多线程对数据访问的 ...
- Java学习笔记-多线程-创建线程的方式
创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...
- .net学习之多线程、线程死锁、线程通信 生产者消费者模式、委托的简单使用、GDI(图形设计接口)常用的方法
1.多线程简单使用(1)进程是不执行代码的,执行代码的是线程,一个进程默认有一个线程(2)线程默认情况下都是前台线程,要所有的前台线程退出以后程序才会退出,进程里默认的线程我们叫做主线程或者叫做UI线 ...
- C#学习笔记之线程 - 通知Signal
通知事件等待句柄 Signal With EventWaitHandle 事件等待句柄常用于通知.当一个线程等待直到接收到另外一个线程发出的信号.事件等待句柄是最简单的信号结构,它与C#事件无关.有三 ...
- Java多线程中线程间的通信
一.使用while方式来实现线程之间的通信 package com.ietree.multithread.sync; import java.util.ArrayList; import java.u ...
随机推荐
- Error while importing sbt project:--创建sbt项目导入文件出错
错误截图如下: Error while importing sbt project: List([info] Loading global plugins from C:\Users\RYJ\.sbt ...
- mysql中的on
左右连接是一个性质所以我这里以左连接为例,写了一个小例子: 用到连接的时候on会常用到, on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录. 简单解释就是假设两个 ...
- JavaScript----简介及基础语法
##JavaScript *概念:一门客户端脚本语言 *运行在客户端浏览器中的.每一个浏览器都有JavaScript的解析引擎. *脚本语言:不需要编译,直接就可以被浏览器解析执行. *功能: *可以 ...
- Docker镜像拉取慢的解决方法
镜像加速器配置: 下文配置引用于阿里云说明文档:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors 1. 安装/升级Docker客户 ...
- Python第五章-内置数据结构05-集合
Python内置数据结构 五.集合(set) python 还提供了另外一种数据类型:set. set用于包含一组无序的不重复对象.所以set中的元素有点像dict的key.这是set与 list的最 ...
- VMware workstation 下Hadoop伪分布式模式安装
详细过程: 1.VMware安装: 2.centos 6 安装 3.jdk下载安装配置 4.Hadoop 安装配置 1.VMware Workstation 安装: https://www.vmwar ...
- 120prop-python3.7 读写.properties文件
120prop-python3.7 读写.properties文件 转载 nature_ph 最后发布于2019-07-30 10:12:05 阅读数 229 收藏 发布于2019-07-30 10: ...
- FastAI 简介
Fastai简介 在深度学习领域,最受学生欢迎的MOOC课程平台有三个:Fast.ai.deeplearning.ai /Coursera和Udacity.Fastai作为其中之一,是一个课程平台,一 ...
- 理解BERT:一个突破性NLP框架的综合指南
概述 Google的BERT改变了自然语言处理(NLP)的格局 了解BERT是什么,它如何工作以及产生的影响等 我们还将在Python中实现BERT,为你提供动手学习的经验 BERT简介 想象一下-- ...
- Nginx 简介与安装
1,简介 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.由俄罗斯的程序设计师Igor Sysoev所开发,供俄 ...