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,记录一下学习过程以备后续查用. 前面讲的线 ...
随机推荐
- PYTHON 得到光标处的句柄
import win32api import win32gui import time if __name__ == '__main__': while True: point = win32api. ...
- python pandas inplace参数
'''pandas 中 inplace 参数在很多函数中都会有,它的作用是:是否在原对象基础上进行修改 inplace = True:不创建新的对象,直接对原始对象进行修改: inplace ...
- VisualEffectGraph基础操作 --创建VEG项目步骤讲解
一:建立VEG项目步骤 首先打开Unity Hub, 使用unity2020.1 新建项目(本技术博客,默认使用unity2020.1 版本演示),选择HDRP 高清渲染管线,确定项目目录与名称. ...
- Spark—local模式环境搭建
Spark--local模式环境搭建 一.Spark运行模式介绍 1.本地模式(loca模式):spark单机运行,一般用户测试和开发使用 2.Standalone模式:构建一个主从结构(Master ...
- 微信小程序云开发-数据库-获取用户添加的数据到数据库
一.列表页面新增[添加商品]按钮 在列表页增加[添加商品]按钮,按钮绑定事件toAdd(),用户点击该按钮跳转到添加商品页面. 在js文件中写toAdd()函数,作用是点击[添加商品]按钮,跳转到[添 ...
- 使用Elastic Job的分片配置加速任务执行和提高资源利用率
上一篇,我们介绍了如何使用Elastic Job实现定时任务.解决了使用@Scheduled来实现时候存在的竞争问题,同时也实现了定时任务的高可用执行. 然而,还有一类问题是我们在做定时任务时候容易出 ...
- Python 接口之request ,headers格式不对
复制heardes格式,模拟请求报错 原因:粗心,headers带了空格
- 使用Maven打包可运行jar和javaagent.jar的区别
简介 javaagent 是 Java1.5 之后引入的新特性,其主要作用是在class被加载之前对其拦截,以插入我们的字节码. java1.5 之前使用的是JVMTI(jvm tool interf ...
- vue目首屏添加skeleton骨架屏
1. 安装插件:npm install vue-skeleton-webpack-plugin 2. 在src目录下创建 Skeleton.vue <template> <div c ...
- []*T *[]T *[]*T 傻傻分不清楚
前言 作为一个 Go 语言新手,看到一切"诡异"的代码都会感到好奇:比如我最近看到的几个方法:伪代码如下: func FindA() ([]*T,error) { } func F ...