对制造者线程和使用者线程进行同步
2011-08-29 22:01 Dirichlet 阅读(340) 评论(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 关键字以及 AutoResetEvent 和 ManualResetEvent 类对主线程和两个辅助线程进行线程同步。有关更多信息,请参见 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