使用AutoResetEvent,ManualResetEvent和ManualResetEventSlim类进行线程间通信

 AutoResetEvent和ManualResetEvent允许线程通过发信号进行通信。

 两者都有两个信号量:True和False。都通过Set()和ReSet()来设置。并且使用WaitOne()的方法阻止当前的线程。

 不同的是AutoResetEvent在调用Set()把信号量释放后(信号量设置为True),然后自动返回到终止状态(信号量为False). 

 线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号。 如果 AutoResetEvent 为非终止状态,则线程会被阻止,并等待当前控制资源的线程通过调用 Set 来通知资源可用。
 调用 Set 向 AutoResetEvent 发信号以释放等待线程。 AutoResetEvent 将保持终止状态,直到一个正在等待的线程被释放,然后自动返回非终止状态。 如果没有任何线程在等待,则状态将无限期地保持为终止状态。
如果当 AutoResetEvent 为终止状态时线程调用 WaitOne,则线程不会被阻止。 AutoResetEvent 将立即释放线程并返回到未触发状态。

 ManualResetEvent在调用Set()后,需要手动调用ReSet()恢复到终止状态。

 ManualResetEventSlim是ManualResetEvent的简化版本,是4.0新增的类。使用Wait()方法来阻止线程。

 MSDN上的代码很好的解释了如何使用:

 Code:

使用AutoResetEvent 

 1    class Example
 2     {
 3         private static AutoResetEvent event_1 = new AutoResetEvent(true); 
 4         private static AutoResetEvent event_2 = new AutoResetEvent(false);
 5 
 6         static void Main()
 7         {
 8             Console.WriteLine("Press Enter to create three threads and start them.\r\n" +
 9                               "The threads wait on AutoResetEvent #1, which was created\r\n" +
10                               "in the signaled state, so the first thread is released.\r\n" +
11                               "This puts AutoResetEvent #1 into the unsignaled state.");
12             Console.ReadLine();
13 
14             for (int i = 1; i < 4; i++)
15             {
16                 Thread t = new Thread(ThreadProc);
17                 t.Name = "Thread_" + i;
18                 t.Start();
19             }
20             Thread.Sleep(1000);
21 
22             for (int i = 0; i < 2; i++)
23             {
24                 Console.WriteLine("Press Enter to release another thread.");
25                 Console.ReadLine();
26                 event_1.Set();
27                 Thread.Sleep(250);
28             }
29 
30             Console.WriteLine("\r\nAll threads are now waiting on AutoResetEvent #2.");
31             for (int i = 0; i < 3; i++)
32             {
33                 Console.WriteLine("Press Enter to release a thread.");
34                 Console.ReadLine();
35                 event_2.Set();
36                 Thread.Sleep(250);
37             }
38 
39             // Visual Studio: Uncomment the following line.
40             //Console.Readline();
41         }
42 
43         static void ThreadProc()
44         {
45             string name = Thread.CurrentThread.Name;
46 
47             Console.WriteLine("{0} waits on AutoResetEvent #1.", name);
48             event_1.WaitOne();
49             Console.WriteLine("{0} is released from AutoResetEvent #1.", name);
50 
51             Console.WriteLine("{0} waits on AutoResetEvent #2.", name);
52             event_2.WaitOne();
53             Console.WriteLine("{0} is released from AutoResetEvent #2.", name);
54 
55             Console.WriteLine("{0} ends.", name);
56         }
57     }
View Code

使用ManualResetEvent

 1    public class Example
 2     {
 3         private static ManualResetEvent mre = new ManualResetEvent(false);
 4 
 5         static void Main()
 6         {
 7             Console.WriteLine("\nStart 3 named threads that block on a ManualResetEvent:\n");
 8 
 9             for (int i = 0; i <= 2; i++)
10             {
11                 Thread t = new Thread(ThreadProc);
12                 t.Name = "Thread_" + i;
13                 t.Start();
14             }
15 
16             Thread.Sleep(500);
17             Console.WriteLine("\nWhen all three threads have started, press Enter to call Set()" +
18                               "\nto release all the threads.\n");
19             Console.ReadLine();
20 
21             mre.Set();
22 
23             Thread.Sleep(500);
24             Console.WriteLine("\nWhen a ManualResetEvent is signaled, threads that call WaitOne()" +
25                               "\ndo not block. Press Enter to show this.\n");
26             Console.ReadLine();
27 
28             for (int i = 3; i <= 4; i++)
29             {
30                 Thread t = new Thread(ThreadProc);
31                 t.Name = "Thread_" + i;
32                 t.Start();
33             }
34 
35             Thread.Sleep(500);
36             Console.WriteLine("\nPress Enter to call Reset(), so that threads once again block" +
37                               "\nwhen they call WaitOne().\n");
38             Console.ReadLine();
39 
40             mre.Reset();
41 
42             // Start a thread that waits on the ManualResetEvent.
43             Thread t5 = new Thread(ThreadProc);
44             t5.Name = "Thread_5";
45             t5.Start();
46 
47             Thread.Sleep(500);
48             Console.WriteLine("\nPress Enter to call Set() and conclude the demo.");
49             Console.ReadLine();
50 
51             mre.Set();
52 
53             // If you run this example in Visual Studio, uncomment the following line:
54             //Console.ReadLine();
55         }
56 
57         private static void ThreadProc()
58         {
59             string name = Thread.CurrentThread.Name;
60 
61             Console.WriteLine(name + " starts and calls mre.WaitOne()");
62 
63             mre.WaitOne();
64 
65             Console.WriteLine(name + " ends.");
66         }
67     }
View Code

使用ManualResetEventSlim

 1    class MRESDemo
 2     {
 3         static void Main()
 4         {
 5             MRES_SetWaitReset();
 6             MRES_SpinCountWaitHandle();
 7             Console.ReadKey();
 8         }
 9         static void MRES_SetWaitReset()
10         {
11             ManualResetEventSlim mres1 = new ManualResetEventSlim(false); // initialize as unsignaled
12             ManualResetEventSlim mres2 = new ManualResetEventSlim(false); // initialize as unsignaled
13             ManualResetEventSlim mres3 = new ManualResetEventSlim(true);  // initialize as signaled
14 
15             var observer = Task.Factory.StartNew(() =>
16             {
17                 mres1.Wait();
18                 Console.WriteLine("observer sees signaled mres1!");
19                 Console.WriteLine("observer resetting mres3...");
20                 mres3.Reset(); 
21                 Console.WriteLine("observer signalling mres2");
22                 mres2.Set();
23             });
24             Console.WriteLine("main thread: mres3.IsSet = {0} (should be true)", mres3.IsSet);
25             Console.WriteLine("main thread signalling mres1");
26             mres1.Set();
27             mres2.Wait();
28 
29             Console.WriteLine("main thread sees signaled mres2!");
30             Console.WriteLine("main thread: mres3.IsSet = {0} (should be false)", mres3.IsSet);
31 
32             observer.Wait(); // make sure that this has fully completed
33             mres1.Dispose();
34             mres2.Dispose();
35             mres3.Dispose();
36         }
37 
38         static void MRES_SpinCountWaitHandle()
39         {
40             // Construct a ManualResetEventSlim with a SpinCount of 1000
41             // Higher spincount => longer time the MRES will spin-wait before taking lock
42             ManualResetEventSlim mres1 = new ManualResetEventSlim(false, 1000);
43             ManualResetEventSlim mres2 = new ManualResetEventSlim(false, 1000);
44 
45             Task bgTask = Task.Factory.StartNew(() =>
46             {
47                 Thread.Sleep(100);
48                 Console.WriteLine("Task signalling both MRESes");
49                 mres1.Set();
50                 mres2.Set();
51             });
52 
53             WaitHandle.WaitAll(new WaitHandle[] { mres1.WaitHandle, mres2.WaitHandle });
54             Console.WriteLine("WaitHandle.WaitAll(mres1.WaitHandle, mres2.WaitHandle) completed.");
55 
56             bgTask.Wait();
57             mres1.Dispose();
58             mres2.Dispose();
59         }
60     }
View Code

 

 

posted on 2014-03-04 00:24  象山  阅读(2127)  评论(0编辑  收藏  举报

导航