.NET并行计算和并发11:并发接口 IProducerConsumerCollection

时间:2024-08-21 15:03:38
  1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Collections.Concurrent;
5 using System.Linq;
6 using System.Threading;
7 using System.Threading.Tasks;
8
9
10 // Sample implementation of IProducerConsumerCollection(T)
11 // -- in this case, a thread-safe stack.
12 public class SafeStack<T> : IProducerConsumerCollection<T>
13 {
14 // Used for enforcing thread-safety
15 private object m_lockObject = new object();
16
17 // We'll use a regular old Stack for our core operations
18 private Stack<T> m_sequentialStack = null;
19
20 //
21 // Constructors
22 //
23 public SafeStack()
24 {
25 m_sequentialStack = new Stack<T>();
26 }
27
28 public SafeStack(IEnumerable<T> collection)
29 {
30 m_sequentialStack = new Stack<T>(collection);
31 }
32
33 //
34 // Safe Push/Pop support
35 //
36 public void Push(T item)
37 {
38 lock (m_lockObject) m_sequentialStack.Push(item);
39 }
40
41 public bool TryPop(out T item)
42 {
43 bool rval = true;
44 lock (m_lockObject)
45 {
46 if (m_sequentialStack.Count == 0) { item = default(T); rval = false; }
47 else item = m_sequentialStack.Pop();
48 }
49 return rval;
50 }
51
52 //
53 // IProducerConsumerCollection(T) support
54 //
55 public bool TryTake(out T item)
56 {
57 return TryPop(out item);
58 }
59
60 public bool TryAdd(T item)
61 {
62 Push(item);
63 return true; // Push doesn't fail
64 }
65
66 public T[] ToArray()
67 {
68 T[] rval = null;
69 lock (m_lockObject) rval = m_sequentialStack.ToArray();
70 return rval;
71 }
72
73 public void CopyTo(T[] array, int index)
74 {
75 lock (m_lockObject) m_sequentialStack.CopyTo(array, index);
76 }
77
78
79
80 //
81 // Support for IEnumerable(T)
82 //
83 public IEnumerator<T> GetEnumerator()
84 {
85 // The performance here will be unfortunate for large stacks,
86 // but thread-safety is effectively implemented.
87 Stack<T> stackCopy = null;
88 lock (m_lockObject) stackCopy = new Stack<T>(m_sequentialStack);
89 return stackCopy.GetEnumerator();
90 }
91
92
93 //
94 // Support for IEnumerable
95 //
96 IEnumerator IEnumerable.GetEnumerator()
97 {
98 return ((IEnumerable<T>)this).GetEnumerator();
99 }
100
101 //
102 // Support for ICollection
103 //
104 public bool IsSynchronized
105 {
106 get { return true; }
107 }
108
109 public object SyncRoot
110 {
111 get { return m_lockObject; }
112 }
113
114 public int Count
115 {
116 get { return m_sequentialStack.Count; }
117 }
118
119 public void CopyTo(Array array, int index)
120 {
121 lock (m_lockObject) ((ICollection)m_sequentialStack).CopyTo(array, index);
122 }
123 }
124
125 public class Program
126 {
127 static void Main()
128 {
129 TestSafeStack();
130
131 // Keep the console window open in debug mode.
132 Console.WriteLine("Press any key to exit.");
133 Console.ReadKey();
134 }
135
136 // Test our implementation of IProducerConsumerCollection(T)
137 // Demonstrates:
138 // IPCC(T).TryAdd()
139 // IPCC(T).TryTake()
140 // IPCC(T).CopyTo()
141 static void TestSafeStack()
142 {
143 SafeStack<int> stack = new SafeStack<int>();
144 IProducerConsumerCollection<int> ipcc = (IProducerConsumerCollection<int>)stack;
145
146 // Test Push()/TryAdd()
147 stack.Push(10); Console.WriteLine("Pushed 10");
148 ipcc.TryAdd(20); Console.WriteLine("IPCC.TryAdded 20");
149 stack.Push(15); Console.WriteLine("Pushed 15");
150
151 int[] testArray = new int[3];
152
153 // Try CopyTo() within boundaries
154 try
155 {
156 ipcc.CopyTo(testArray, 0);
157 Console.WriteLine("CopyTo() within boundaries worked, as expected");
158 }
159 catch (Exception e)
160 {
161 Console.WriteLine("CopyTo() within boundaries unexpectedly threw an exception: {0}", e.Message);
162 }
163
164 // Try CopyTo() that overflows
165 try
166 {
167 ipcc.CopyTo(testArray, 1);
168 Console.WriteLine("CopyTo() with index overflow worked, and it SHOULD NOT HAVE");
169 }
170 catch (Exception e)
171 {
172 Console.WriteLine("CopyTo() with index overflow threw an exception, as expected: {0}", e.Message);
173 }
174
175 // Test enumeration
176 Console.Write("Enumeration (should be three items): ");
177 foreach (int item in stack) Console.Write("{0} ", item);
178 Console.WriteLine("");
179
180 // Test TryPop()
181 int popped = 0;
182 if (stack.TryPop(out popped))
183 {
184 Console.WriteLine("Successfully popped {0}", popped);
185 }
186 else Console.WriteLine("FAILED to pop!!");
187
188 // Test Count
189 Console.WriteLine("stack count is {0}, should be 2", stack.Count);
190
191 // Test TryTake()
192 if (ipcc.TryTake(out popped))
193 {
194 Console.WriteLine("Successfully IPCC-TryTaked {0}", popped);
195 }
196 else Console.WriteLine("FAILED to IPCC.TryTake!!");
197 }
198 }
199