C#线程间互相通信
- 格式:pdf
- 大小:82.37 KB
- 文档页数:4
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中加上⼀⾏代码,如下:
复制代码
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();