C#多线程---Event类实现线程同步
一、简介
我们使用类(.net Framework中的类,如 AutoResetEvent, Semaphore类等)的方法来实现线程同步的时候,其实内部是调用操作系统的内核对象来实现的线程同步。
System.Threading命名空间中提供了一个WaitHandle 的抽象基类,此类就是包装了一个Windows内核对象的句柄(句柄可以理解为标示了对象实例的一个数字),在.net Framework中提供了从WaitHandle类中派生的类。继承关系如下所示:
WaitHandle
EventWaitHandle
AutoResetEvent
ManualResetEvent
Semaphore
Mutex
当我们在使用 AutoResetEvent,ManualResetEvent,Semaphore,Mutex这些类的时候,用构造函数来实例化这些类的对象时,其内部都调用了Win32 CreateEvent或CreateEvent函数,或CreateSemaphore或者CreateMutex函数,这些函数调用返回的句柄值都保存在WaitHandle基类定义的SafeWaitHandle字段中。
二、AutoResetEvent (自动重置事件)
AutoResetEvent 在获得信号后,会自动将事件设置为无信号状态。
例1:事件初始化为无信号状态,主线程等待一段时间将事件设置为有信号状态
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7
8 namespace ThreadEvent
9 {
10 class Program
11 {
12 public static AutoResetEvent autoEvent = new AutoResetEvent(false);
13 static void Main(string[] args)
14 {
15 Task task = new Task(ThreadFunc);
16 task.Start();
17 Console.WriteLine($"{DateTime.Now} Printed in main");
18 Thread.Sleep(5000);
19 Console.WriteLine($"{DateTime.Now} Set signal in main");
20 autoEvent.Set();
21 Console.Read();
22 }
23 private static void ThreadFunc()
24 {
25 PrintThreadInfo($"Printed in thread func");
26 }
27 private static void PrintThreadInfo(string info)
28 {
29 if (autoEvent.WaitOne())
30 {
31 //autoEvent.WaitOne();
32 Console.WriteLine($"{DateTime.Now} {info}");
33 Console.WriteLine($"{DateTime.Now} ThreadId:{Thread.CurrentThread.ManagedThreadId}\nIsBackgroundThread:{Thread.CurrentThread.IsBackground}\nIsThreadPoolThread:{Thread.CurrentThread.IsThreadPoolThread}");
34 }
35
36 }
37 }
38 }
运行结果如下:

例2:事件初始化为无信号状态,主线程等待一段时间将事件设置为有信号状态,子线程连续两次Wait,观察第二次Wait的结果
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7
8 namespace ThreadEvent
9 {
10 class Program
11 {
12 public static AutoResetEvent autoEvent = new AutoResetEvent(false);
13 static void Main(string[] args)
14 {
15 Task task = new Task(ThreadFunc);
16 task.Start();
17 Console.WriteLine($"{DateTime.Now} Printed in main");
18 Thread.Sleep(5000);
19 Console.WriteLine($"{DateTime.Now} Set signal in main");
20 autoEvent.Set();
21 Console.Read();
22 }
23 private static void ThreadFunc()
24 {
25 PrintThreadInfo($"Printed in thread func");
26 }
27 private static void PrintThreadInfo(string info)
28 {
29 if (autoEvent.WaitOne())
30 {
31 if (autoEvent.WaitOne(4000))
32 {
33 Console.WriteLine($"{DateTime.Now} {info}");
34 Console.WriteLine($"{DateTime.Now} ThreadId:{Thread.CurrentThread.ManagedThreadId}\nIsBackgroundThread:{Thread.CurrentThread.IsBackground}\nIsThreadPoolThread:{Thread.CurrentThread.IsThreadPoolThread}");
35 }
36 else
37 {
38 Console.ForegroundColor = ConsoleColor.Red;
39 Console.WriteLine($"{DateTime.Now} WaitOne timeout!");
40 Console.ResetColor();
41 }
42 }
43
44 }
45 }
46 }
运行结果如下:

三、ManualResetEvent(手动重置事件)
ManualResetEvent在获得信号后,会一直保持有信号状态,除非我们手动调用Reset来将事件设置为无信号状态。
例1:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7
8 namespace ThreadEvent
9 {
10 class Program
11 {
12 public static ManualResetEvent autoEvent = new ManualResetEvent(false);
13 static void Main(string[] args)
14 {
15 Task task = new Task(ThreadFunc);
16 task.Start();
17 Console.WriteLine($"{DateTime.Now} Printed in main");
18 Thread.Sleep(5000);
19 Console.WriteLine($"{DateTime.Now} Set signal in main");
20 autoEvent.Set();
21 Console.Read();
22 }
23 private static void ThreadFunc()
24 {
25 PrintThreadInfo($"Printed in thread func");
26 }
27 private static void PrintThreadInfo(string info)
28 {
29 if (autoEvent.WaitOne())
30 {
31 //autoEvent.Reset();
32 if (autoEvent.WaitOne(4000))
33 {
34 Console.WriteLine($"{DateTime.Now} {info}");
35 Console.WriteLine($"{DateTime.Now} ThreadId:{Thread.CurrentThread.ManagedThreadId}\nIsBackgroundThread:{Thread.CurrentThread.IsBackground}\nIsThreadPoolThread:{Thread.CurrentThread.IsThreadPoolThread}");
36 }
37 else
38 {
39 Console.ForegroundColor = ConsoleColor.Red;
40 Console.WriteLine($"{DateTime.Now} WaitOne timeout!");
41 Console.ResetColor();
42 }
43 }
44
45 }
46 }
47 }
运行结果如下:

C#多线程---Event类实现线程同步的更多相关文章
- C#多线程---Mutex类实现线程同步
一.例子 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 ...
- C#多线程:深入了解线程同步lock,Monitor,Mutex,同步事件和等待句柄(中)
本篇继续介绍WaitHandler类及其子类 Mutex,ManualResetEvent,AutoResetEvent的用法..NET中线程同步的方式多的让人看了眼花缭乱,究竟该怎么去理解呢?其实, ...
- Python多线程(2)——线程同步机制
本文介绍Python中的线程同步对象,主要涉及 thread 和 threading 模块. threading 模块提供的线程同步原语包括:Lock.RLock.Condition.Event.Se ...
- java多线程(2) 线程同步
我们对线程访问同一份资源的多个线程之间,来进行协调的这个东西,就是线程同步. 例子1:模拟了多个线程操作同一份资源,可能带来的问题: package com.cy.thread; public c ...
- Java多线程系列三——实现线程同步的方法
两种实现线程同步的方法 方法 特性 synchronized 不需要显式地加解锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁 ...
- Java多线程之简单的线程同步实例
数据类: package Thread.MyCommon; public class Data { public int num = 0; public synchronized int getEve ...
- iOS多线程各种安全锁介绍 - 线程同步
一.atomic介绍 github对应Demo:https://github.com/Master-fd/LockDemo 在iOS中,@property 新增属性时,可以增加atomic选项,ato ...
- win32多线程 (二)线程同步之临界区 (critical sections)
所谓critical sections 意指一小块“用来处理一份被共享之资源”的程序代码.你可能必须在程序的许多地方处理这一块可共享的资源.所有这些程序代码可以被同一个critical sectio ...
- C#线程学习笔记五:线程同步--事件构造
本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/23/Event_Constructor.html,记录一下学习过程以备后续查用. 前面讲的线 ...
随机推荐
- 团队开发day04
通过myurl.openConnection()连接一直连接失败,问题解决: 在一般的Java Web程序开发中,我们通常使用localhost或者127.0.0.1来访问本机的Web服务, 但是如果 ...
- [刘阳Java]_Spring入门_第1讲
Spring框架在企业中的使用非常多,优势明显.所以学好Spring框架肯定不言而喻.今天我们给大家介绍Spring的入门 1. 对于初学者来说我们要学习Spring框架中的哪些技术,这个有必要了解一 ...
- Java多线程(下)
线程同步 当多个线程访问一个对象时,有可能会发生污读,即读取到未及时更新的数据,这个时候就需要线程同步. 线程同步: 即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线 ...
- SpringBoot之了解自动配置原理
承接上文: import注解的使用: 作用:引用时,容器自动创建出这填写的类型的组件,默认组件的名字就是全类名. 往容器中添加两个组件 @Import({User.class, DBHelper.cl ...
- 基于Redisson实现分布式锁源码解读
文章目录 一.分布式锁的概念 和 使用场景 二.将redis官网对于分布式锁(红锁)的定义和Redisson实现做概括性总结 三.基于Redisson的分布式实现方案 四.加锁过程分析 五.锁重入过程 ...
- videojs踩过的坑
1.videojs-contrib-hls 在webpack中不能用,解决方法:window.videojs = videojs:出处 https://github.com/videojs/video ...
- java封装基础详解
java封装基础详解 java的封装性即是信息隐藏,把对象的属性和行为结合成一个相同的独立单体,并尽可能地隐藏对象的内部细节. 封装的特性是对属性来讲的. 封装的目标就是要实现软件部件的"高 ...
- SAS启动时自动执行代码
有时候我们希望SAS启动时自动执行已经编写好的程序,可以按照以下方法实现: 首先正常打开SAS,编写我们想要让SAS启动时自动执行的代码,例如获取桌面文件夹路径,以便在其他程序中引用这个路径. pro ...
- 开机时自动启动的AutoHotkey脚本 2019年07月08日19时06分
;;; 开机时自动启动的AutoHotkey脚本;; 此脚本修改时间 2019年06月18日20时48分;; 计时器创建代码段 ------------------------------------ ...
- Tensor:Pytorch神经网络界的Numpy
摘要:Tensor,它可以是0维.一维以及多维的数组,你可以将它看作为神经网络界的Numpy,它与Numpy相似,二者可以共享内存,且之间的转换非常方便. 本文分享自华为云社区<Tensor:P ...