C# 线程间互相通信
C#线程间互相通信主要用到两个类:AutoResetEvent和ManualResetEvent.
一、AutoResetEvent
AutoResetEvent 允许线程通过发信号互相通信,线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号。 如果 AutoResetEvent 为非终止状态,则线程会被阻止,并等待当前控制资源的线程通过调用 Set 来通知资源可用。
下面我用吃快餐的例子来说明这个问题,吃快餐的时候都会排队付款,收银员发送收款通知,客户依次付钱,代码如下:
复制代码
1 class Program
2 {
3 //若要将初始状态设置为终止,则为 true;若要将初始状态设置为非终止,则为 false
4 static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
5
6 static void Main(string[] args)
7 {
8 Thread t1 = new Thread(() =>
9 {
10 Console.WriteLine("客户1在排队等待付钱…");
11
12 //客户1调用AutoResetEvent上的WaitOne来等待付钱通知
13 autoResetEvent.WaitOne();
14 Console.WriteLine("通知来了,客户1付钱");
15 });
16 t1.IsBackground = true;
17 t1.Start();
18
19 Pay();//发送通知
20 Console.ReadKey();
21 }
22
23 static void Pay()
24 {
25 string tip = Console.ReadLine();
26 if (tip == "next")
27 {
28 autoResetEvent.Set();//收银员发送付钱通知,通过调用Set来通知客户付钱
29 }
30 }
31 }
复制代码
运行在屏幕中打印:
客户1在排队等待付钱…
等收银员说"next"的时候,向客户1发送付钱通知(autoResetEvent.Set()),屏幕打印:
客户1在排队等待付钱…
next
通知来了,客户1付钱!
AutoResetEvent类一次只能通知一个等待的线程,且通知一次过后会立即将AutoResetEvent对象的状态置为false,也就是如果有两个客户都在等待收银员通知,AutoResetEvent对象的set方法只能通知到第一个客户,代码和效果如下:
复制代码
1 class Program
2 {
3 //若要将初始状态设置为终止,则为 true;若要将初始状态设置为非终止,则为 false.
4 static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
5
6 static void Main(string[] args)
7 {
8 Thread t1 = new Thread(() =>
9 {
10 Console.WriteLine("客户1在排队等待付钱…");
11
12 //客户1调用AutoResetEvent上的WaitOne来等待付钱通知
13 autoResetEvent.WaitOne();
14 Console.WriteLine("通知来了,客户1付钱");
15 });
16 t1.IsBackground = true;
17 t1.Start();
18
19 Thread t2 = new Thread(() =>
20 {
21 Console.WriteLine("客户2在排队等待付钱…");
22
23 //客户2调用AutoResetEvent上的WaitOne来等待付钱通知
24 autoResetEvent.WaitOne();
25 Console.WriteLine("通知来了,客户2付钱!");
26 });
27 t2.IsBackground = true;
28 t2.Start();
29
30 Pay();//发送通知
31
32 Console.ReadKey();
33 }
34
35 static void Pay()
36 {
37 string tip = Console.ReadLine();
38 if (tip == "next")
39 {
40 autoResetEvent.Set();//收银员发送付钱通知,通过调用Set来通知客户付钱
41 }
42 }
43 }
复制代码
运行后屏幕打印:
客户1在排队等待付钱…
客户1在排队等待付钱…
next
通知来了,客户1付钱!
这就说明在通知完客户1后,autoResetEvent 的状态又被置为了false,这时如果要通知到客户2,就需要在通知完客户1后,再执行一次通知,在线程1中加上一行代码,如下:
复制代码act答案 www.yzyxedu.com
1 Thread t1 = new Thread(() =>
2 {
3 Console.WriteLine("客户1在排队等待付钱…");
4
5 //客户1调用AutoResetEvent上的WaitOne来等待付钱通知
6 autoResetEvent.WaitOne();
7 Console.WriteLine("通知来了,客户1付钱");
8
9 autoResetEvent.Set();//让其再通知下个客户
10 });
复制代码
运行后屏幕打印:
客户1在排队等待付钱…
客户1在排队等待付钱…
next
通知来了,客户1付钱!
通知来了,客户2付钱!
这也就说明每调用一次Set,只有一个线程会解除等待,换句话说,有多少个线程就要调用多少次Set,线程才会全部继续。
二、ManualResetEvent
在AutoResetEvent中,如果要通知两个线程,则Set方法要被执行两次,也以快餐店的例子做了举例,但如果有一天客户1中彩票了,要请部门的10个同事吃饭,也就是说只要Set一次,所有在等待的线程都会解除等待,相当于收银员只收一次钱,10个人都可以通过收银去吃饭,这时我们就要用到ManualResetEvent类,它的用法和AutoResetEvent基本一样,区别就在于它是一量Set方法发出通知后,要再次阻塞的话就需要手动去修改,也就是调用Reset方法,代码如下:
复制代码
1 class Program
2 {
3 //若要将初始状态设置为终止,则为 true;若要将初始状态设置为非终止,则为 false.
4 static ManualResetEvent manualResetEvent = new ManualResetEvent(false);
5
6 static void Main(string[] args)
7 {
8 Thread t1 = new Thread(() =>
9 {
10 Console.WriteLine("客户1在排队等待付钱…");
11
12 //客户1调用manualResetEvent上的WaitOne来等待付钱通知
13 manualResetEvent.WaitOne();
14 Console.WriteLine("已经有人请客,客户1不用付钱");
15 });
16 t1.IsBackground = true;
17 t1.Start();
18
19 Thread t2 = new Thread(() =>
20 {
21 Console.WriteLine("客户2在排队等待付钱…");
22
23 //客户2调用manualResetEvent上的WaitOne来等待付钱通知
24 manualResetEvent.WaitOne();
25 Console.WriteLine("已经有人请客,客户2不用付钱!");
26 });
27 t2.IsBackground = true;
28 t2.Start();
29
30 Pay();//发送通知
31
32 Console.ReadKey();
33 }
34
35 static void Pay()
36 {
37 string tip = Console.ReadLine();
38 if (tip == "next")
39 {
40 manualResetEvent.Set();//收银员发送付钱通知,通过调用Set来通知客户付钱
41 }
42 }
43 }
复制代码
运行后屏幕打印:
客户1在排队等待付钱…
客户1在排队等待付钱…
next
已经有人请客,客户1不用付钱!
已经有人请客,客户2不用付钱!
如果收银员在发送通知后5秒就下班了,就不能再收钱了,这时就要把通知重置掉,让没接到通知的客户继续处于继续等待,代码如下:
复制代码
1 class Program
2 {
3 //若要将初始状态设置为终止,则为 true;若要将初始状态设置为非终止,则为 false.
4 static ManualResetEvent manualResetEvent = new ManualResetEvent(false);
5
6 static void Main(string[] args)
7 {
8 Thread t1 = new Thread(() =>
9 {
10 Console.WriteLine("客户1在排队等待付钱…");
11
12 //客户1调用manualResetEvent上的WaitOne来等待付钱通知
13 manualResetEvent.WaitOne();
14 Console.WriteLine("已经有人请客,客户1不用付钱");
15 });
16 t1.IsBackground = true;
17 t1.Start();
18
19 Thread t2 = new Thread(() =>
20 {
21 Console.WriteLine("客户2在排队等待付钱…");
22
23 Thread.Sleep(8000);//客户2发呆了8秒,这时收银员已经下班,要继续等待
24 //客户2调用manualResetEvent上的WaitOne来等待付钱通知
25 manualResetEvent.WaitOne();
26 Console.WriteLine("已经有人请客,客户2不用付钱!");
27 });
28 t2.IsBackground = true;
29 t2.Start();
30
31 Pay();//发送通知
32
33 Console.ReadKey();
34 }
35
36 static void Pay()
37 {
38 string tip = Console.ReadLine();
39 if (tip == "next")
40 {
41 manualResetEvent.Set();//收银员发送付钱通知,通过调用Set来通知客户付钱
42
43 Timer timer = new Timer(StopPay, null, 0, 5000);//5秒钟后收银员下班了,线程要重新等待了
44 }
45 }
46
47 static void StopPay(object s)
48 {
49 manualResetEvent.Reset();
50 Console.WriteLine("收银员下班, 后面的客户要继续等待");
51 }
52 }
复制代码
运行后屏幕打印:
客户1在排队等待付钱…
客户1在排队等待付钱…
next
已经有人请客,客户1不用付钱!
收银员下班,后面的客户要继续等待
总结
AutoResetEvent和ManualResetEvent的主要区别就在于:AutoResetEvent一次只能通知一个等待线程,通知后自动关闭; 而ManualResetEvent一次可通知很多个等待的线程,但要关闭需要调用Reset方法手动关闭托福答案 www.yztrans.com
C# 线程间互相通信的更多相关文章
- iOS开发多线程篇—线程间的通信
iOS开发多线程篇—线程间的通信 一.简单说明 线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个线程传递数据给另1个线程 在1个线程中执行完特定任 ...
- Java核心知识点学习----多线程并发之线程间的通信,notify,wait
1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...
- java多线程详解(6)-线程间的通信wait及notify方法
Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New) ...
- iOS边练边学--多线程NSOperation介绍,子类实现多线程的介绍(任务和队列),队列的取消、暂停(挂起)和恢复,操作依赖与线程间的通信
一.NSOperation NSOperation和NSOperationQueue实现多线程的具体步骤 先将需要执行的操作封装到一个NSOperation对象中 然后将NSOperation对象添加 ...
- 新建线程与UI线程间的通信
现在用一个实例来演示一下自己的新建线程与UI线程间的通信. UI界面包含3个控件: 一个输入框,用来输入数字: 一个显示框,用来显示从2开始,到输入数字之间的所有质数: 一个按钮,点击后获取输入框输入 ...
- QThread与其他线程间相互通信
转载请注明链接与作者huihui1988 QThread的用法其实比较简单,只需要派生一个QThread的子类,实现其中的run虚函数就大功告成, 用的时候创建该类的实例,调用它的start方法即可. ...
- Handler不同线程间的通信
转http://www.iteye.com/problems/69457 Activity启动后点击一个界面按钮后会开启一个服务(暂定为padService),在padService中会启动一个线程( ...
- Java多线程中线程间的通信
一.使用while方式来实现线程之间的通信 package com.ietree.multithread.sync; import java.util.ArrayList; import java.u ...
- C# 线程间互相通信 AutoResetEvent和ManualResetEvent
C#线程间互相通信主要用到两个类:AutoResetEvent和ManualResetEvent. 一.AutoResetEvent AutoResetEvent 允许线程通过发信号互相通信,线程通过 ...
随机推荐
- 解决Mac OS X Lion狮子系统及win7多分区教程
[绿茶教程]解决Mac OS X Lion狮子系统及win7多分区教程 工具/原料 8G的u盘制作lion系统安装盘 步骤/方法 插入U盘---开机---按住左下角“Option”键(alt ...
- 爬虫技术实战 | WooYun知识库
爬虫技术实战 | WooYun知识库 爬虫技术实战 大数据分析与机器学习领域Python兵器谱-大数据邦-微头条(wtoutiao.com) 大数据分析与机器学习领域Python兵器谱
- Div 3 - SGU 105(找规律)
分析:很容易知道序列1,2,3, 4,5, 6......与3的关系就是1,2, 0,1, 2,0,......如果是在一个数后面添加一个数就变成了这种序列1, 0, 0, 1, 0, 0, 1, 0 ...
- ecshop获取客户端操作系统
<?php /** * 获得客户端的操作系统 * * @access private * @return void */ function get_os() { if (empty($_SERV ...
- Java Web中资源的访问路径
在web应用中,以“/”开头的是绝对路径,不以“/”开头的是相对路径. 在服务器端,通常都使用绝对路径.例如web.xml.struts.xml.servlet等的访问路径都是以“/”开始. 服务 ...
- 关于GCC的理解——On the understanding of the GCC
GCC 有超过100个的编译选项可用. 这些选项中的许多你可能永远都不会用到, 但一些主要的选项将会频繁用到. 很多的 GCC 选项包括一个以上的字符. 因此你必须为每个选项指定各自的连字符, 并且就 ...
- crontab 定时任务 每过多少分钟执行
被下面的问题纠结了一会 记录一下以备提醒 每过5分钟执行 */ * * * * curl localhost/system/dns/dnns.php?ac=ToDNS 每小时的第五分钟执行 0 * * ...
- android 在布局中动态添加控件
第一步 final LayoutInflater inflater = LayoutInflater.from(this); 第二步:获取需要被添加控件的布局 final LinearLayout l ...
- Java实现平衡二叉树(AVLTree)的构建
近期在学习数据结构上关于平衡二叉树的知识,看了严老师的思路,感觉用java写出递归的构建方式有点困难,由于当中的递归须要把引用传进去,所以感觉是要实现起来比較麻烦,所以就首先想到使用非递归的方式来实现 ...
- Android如何创建背景透明的Dialog
一:控制Dialog 的背景方法:1.定义一个无背景主题主题<!--去掉背景Dialog--> <style name="NobackDialog" parent ...