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();