代码改变世界

对制造者线程和使用者线程进行同步

2011-08-29 22:01  Dirichlet  阅读(345)  评论(0编辑  收藏  举报

初始化如下:

AutoResetEvent autoRestEvent = new AutoResetEvent(false);

等待线程如下:

1 Task.Factory.StartNew(()=> {
2          if (autoRestEvent.WaitOne() == true)
3          {
4                Console.WriteLine("I got the signal");
5          }
6 });

触发事件的线程如下:

autoRestEvent.Set();

 

1. 触发事件的线程autoRestEvent.Set()发出信号;

2. 等待线程autoRestEvent.WaitOne()得到信号,并立刻将事件重置为无信号状态,开始往后执行。

3. 可以像1,2步一样继续使用Set, WaitOne进行同步。

AutoResetEvent与ManualResetEvent区别就是,manualResetEvent.WaitOne得到信号后,会一直处于有信号状态,不会自动重置事件为无信号状态,不能自动的反复使用set,waitOne,除非手动做reset。

 

下面的示例演示使用 lock 关键字以及 AutoResetEventManualResetEvent 类对主线程和两个辅助线程进行线程同步。有关更多信息,请参见 lock 语句(C# 参考)

该示例创建两个辅助线程。一个线程生成元素并将它们存储在非线程安全的泛型队列中。有关更多信息,请参见 Queue<T>。另一个线程使用此队列中的项。另外,主线程定期显示队列的内容,以便该队列可由三个线程进行访问。lock 关键字用于同步对队列的访问,以确保队列的状态不会被破坏。

除了只是使用 lock 关键字来防止同时访问以外,还可以用两个事件对象提供进一步的同步。一个事件对象用来通知辅助线程终止,另一个事件对象由制造者线程用来在有新项添加到队列中时通知使用者线程。这两个事件对象封装在一个名为 SyncEvents 的类中。这使事件可以轻松传递给表示制造者线程和使用者线程的对象。SyncEvents 类按如下方式定义:

  1 using System;
  2 using System.Threading;
  3 using System.Collections;
  4 using System.Collections.Generic;
  5 
  6 public class SyncEvents
  7 {
  8     public SyncEvents()
  9     {
 10         _newItemEvent = new AutoResetEvent(false);
 11         _exitThreadEvent = new ManualResetEvent(false);
 12         _eventArray = new WaitHandle[2];
 13         _eventArray[0] = _newItemEvent;
 14         _eventArray[1] = _exitThreadEvent;
 15     }
 16 
 17     public EventWaitHandle ExitThreadEvent
 18     {
 19         get { return _exitThreadEvent; }
 20     }
 21     public EventWaitHandle NewItemEvent
 22     {
 23         get { return _newItemEvent; }
 24     }
 25     public WaitHandle[] EventArray
 26     {
 27         get { return _eventArray; }
 28     }
 29 
 30     private EventWaitHandle _newItemEvent;
 31     private EventWaitHandle _exitThreadEvent;
 32     private WaitHandle[] _eventArray;
 33 }
 34 public class Producer 
 35 {
 36     public Producer(Queue<int> q, SyncEvents e)
 37     {
 38         _queue = q;
 39         _syncEvents = e;
 40     }
 41     // Producer.ThreadRun
 42     public void ThreadRun()
 43     {
 44         int count = 0;
 45         Random r = new Random();
 46         while (!_syncEvents.ExitThreadEvent.WaitOne(0, false))
 47         {
 48             lock (((ICollection)_queue).SyncRoot)
 49             {
 50                 while (_queue.Count < 20)
 51                 {
 52                     _queue.Enqueue(r.Next(0,100));
 53                     _syncEvents.NewItemEvent.Set();
 54                     count++;
 55                 }
 56             }
 57         }
 58         Console.WriteLine("Producer thread: produced {0} items", count);
 59     }
 60     private Queue<int> _queue;
 61     private SyncEvents _syncEvents;
 62 }
 63 
 64 public class Consumer
 65 {
 66     public Consumer(Queue<int> q, SyncEvents e)
 67     {
 68         _queue = q;
 69         _syncEvents = e;
 70     }
 71     // Consumer.ThreadRun
 72     public void ThreadRun()
 73     {
 74         int count = 0;
 75         while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1)
 76         {
 77             lock (((ICollection)_queue).SyncRoot)
 78             {
 79                 int item = _queue.Dequeue();
 80             }
 81             count++;
 82         } 
 83         Console.WriteLine("Consumer Thread: consumed {0} items", count);
 84     }
 85     private Queue<int> _queue;
 86     private SyncEvents _syncEvents;
 87 }
 88 
 89 public class ThreadSyncSample
 90 {
 91     private static void ShowQueueContents(Queue<int> q)
 92     {
 93         lock (((ICollection)q).SyncRoot)
 94         {
 95             foreach (int item in q)
 96             {
 97                 Console.Write("{0} ", item);
 98             }
 99         }
100         Console.WriteLine();
101     }
102 
103     static void Main()
104     {
105         Queue<int> queue = new Queue<int>();
106         SyncEvents syncEvents = new SyncEvents();
107 
108         Console.WriteLine("Configuring worker threads...");
109         Producer producer = new Producer(queue, syncEvents);
110         Consumer consumer = new Consumer(queue, syncEvents);
111         Thread producerThread = new Thread(producer.ThreadRun);
112         Thread consumerThread = new Thread(consumer.ThreadRun);
113 
114         Console.WriteLine("Launching producer and consumer threads...");        
115         producerThread.Start();
116         consumerThread.Start();
117 
118         for (int i=0; i<4; i++)
119         {
120             Thread.Sleep(2500);
121             ShowQueueContents(queue);
122         }
123 
124         Console.WriteLine("Signaling threads to terminate...");
125         syncEvents.ExitThreadEvent.Set();
126 
127         producerThread.Join();
128         consumerThread.Join();
129     }
130 
131 }

 

参考:http://msdn.microsoft.com/zh-cn/library/yy12yx1f(v=VS.90).aspx