source: other-projects/playing-in-the-street/summer-2013/trunk/Microsoft.Kinect.Toolkit/ThreadSafeCollection.cs@ 28895

Last change on this file since 28895 was 28895, checked in by davidb, 10 years ago

Base Kinect Project

File size: 15.6 KB
Line 
1//-----------------------------------------------------------------------
2// <copyright file="ThreadSafeCollection.cs" company="Microsoft Corporation">
3// Copyright (c) Microsoft Corporation. All rights reserved.
4// </copyright>
5// <summary>
6// A list with locking semantics so it can be used cross-thread.
7// </summary>
8//-----------------------------------------------------------------------
9
10
11namespace Microsoft.Kinect.Toolkit
12{
13 using System;
14 using System.Collections;
15 using System.Collections.Generic;
16
17 /// <summary>
18 /// IList implementation with locking on all operations.
19 /// </summary>
20 /// <typeparam name="T">Type of generic IList to implement.</typeparam>
21 public sealed class ThreadSafeCollection<T> : IList<T>
22 {
23 /// <summary>
24 /// Lock object to use for all operations.
25 /// </summary>
26 private readonly object lockObject;
27
28 /// <summary>
29 /// Wrapped collection object.
30 /// </summary>
31 private readonly List<T> list = new List<T>();
32
33 /// <summary>
34 /// Initializes a new instance of the ThreadSafeCollection class with a new lock.
35 /// </summary>
36 public ThreadSafeCollection() : this(new object())
37 {
38 }
39
40 /// <summary>
41 /// Initializes a new instance of the ThreadSafeCollection class with an existing new lock.
42 /// </summary>
43 /// <param name="existingLock">Existing lock to use for this collection.</param>
44 public ThreadSafeCollection(object existingLock)
45 {
46 this.lockObject = existingLock;
47 }
48
49 /// <summary>
50 /// Gets the number of elements actually contained in the ThreadSafeCollection&lt;T&gt;.
51 /// </summary>
52 public int Count
53 {
54 get
55 {
56 lock (this.lockObject)
57 {
58 return list.Count;
59 }
60 }
61 }
62
63 /// <summary>
64 /// Gets a value indicating whether the collection is read only. Returns true.
65 /// </summary>
66 public bool IsReadOnly
67 {
68 get
69 {
70 lock (this.lockObject)
71 {
72 return false;
73 }
74 }
75 }
76
77 /// <summary>
78 /// Gets or sets the element at the specified index.
79 /// </summary>
80 /// <param name="index">The zero-based index of the element to get or set.</param>
81 /// <returns>The element at the specified index.</returns>
82 public T this[int index]
83 {
84 get
85 {
86 lock (this.lockObject)
87 {
88 return list[index];
89 }
90 }
91
92 set
93 {
94 lock (this.lockObject)
95 {
96 list[index] = value;
97 }
98 }
99 }
100
101 /// <summary>
102 /// Adds an object to the end of the ThreadSafeCollection&lt;T&gt;.
103 /// </summary>
104 /// <param name="item">
105 /// The object to be added to the end of the ThreadSafeCollection&lt;T&gt;.
106 /// The value can be null for reference types.
107 /// </param>
108 public void Add(T item)
109 {
110 lock (this.lockObject)
111 {
112 list.Add(item);
113 }
114 }
115
116 /// <summary>
117 /// Removes all elements from the ThreadSafeCollection&lt;T&gt;.
118 /// </summary>
119 public void Clear()
120 {
121 lock (this.lockObject)
122 {
123 list.Clear();
124 }
125 }
126
127 /// <summary>
128 /// Determines whether an element is in the ThreadSafeCollection&lt;T&gt;.
129 /// </summary>
130 /// <param name="item">
131 /// The object to locate in the ThreadSafeCollection&lt;T&gt;. The value
132 /// can be null for reference types.
133 /// </param>
134 /// <returns>
135 /// true if item is found in the ThreadSafeCollection&lt;T&gt;; otherwise,
136 /// false.
137 /// </returns>
138 public bool Contains(T item)
139 {
140 lock (this.lockObject)
141 {
142 return list.Contains(item);
143 }
144 }
145
146 /// <summary>
147 /// Copies the entire ThreadSafeCollection&lt;T&gt; to a compatible one-dimensional
148 /// array, starting at the beginning of the target array.
149 /// </summary>
150 /// <param name="array">
151 /// The one-dimensional System.Array that is the destination of the elements
152 /// copied from ThreadSafeCollection&lt;T&gt;. The System.Array must have
153 /// zero-based indexing.
154 /// </param>
155 /// <param name="arrayIndex">
156 /// The zero-based index in array at which copying begins.
157 /// </param>
158 /// <exception cref="System.ArgumentNullException">Array is null.</exception>
159 /// <exception cref="System.ArgumentOutOfRangeException">ArrayIndex is less than 0.</exception>
160 /// <exception cref="System.ArgumentException">
161 /// The number of elements in the source ThreadSafeCollection&lt;T&gt; is
162 /// greater than the available space from arrayIndex to the end of the destination
163 /// array.
164 /// </exception>
165 public void CopyTo(T[] array, int arrayIndex)
166 {
167 lock (this.lockObject)
168 {
169 list.CopyTo(array, arrayIndex);
170 }
171 }
172
173 /// <summary>
174 /// Copies the entire ThreadSafeCollection&lt;Tgt; to a compatible one-dimensional
175 /// array, starting at the beginning of the target array.
176 /// </summary>
177 /// <param name="array">
178 /// The one-dimensional System.Array that is the destination of the elements
179 /// copied from System.Collections.Generic.List&lt;Tgt;. The System.Array must have
180 /// zero-based indexing.
181 /// </param>
182 /// <exception cref="System.ArgumentNullException">Array is null.</exception>
183 /// <exception cref="System.ArgumentException">
184 /// The number of elements in the source ThreadSafeCollection&lt;Tgt; is
185 /// greater than the number of elements that the destination array can contain.
186 /// </exception>
187 public void CopyTo(T[] array)
188 {
189 lock (this.lockObject)
190 {
191 list.CopyTo(array);
192 }
193 }
194
195 /// <summary>
196 /// Adds the elements of the specified collection to the end of the ThreadSafeCollection&lt;T&gt;.
197 /// </summary>
198 /// <param name="collection">
199 /// The collection whose elements should be added to the end of the ThreadSafeCollection&lt;T&gt;.
200 /// The collection itself cannot be null, but it can contain elements that are
201 /// null, if type T is a reference type.
202 /// </param>
203 /// <exception cref="System.ArgumentNullException">Collection is null.</exception>
204 public void AddRange(IEnumerable<T> collection)
205 {
206 lock (this.lockObject)
207 {
208 list.AddRange(collection);
209 }
210 }
211
212 /// <summary>
213 /// Searches for the specified object and returns the zero-based index of the
214 /// first occurrence within the entire ThreadSafeCollection&lt;T&gt;.
215 /// </summary>
216 /// <param name="item">
217 /// The object to locate in the ThreadSafeCollection&lt;T&gt;. The value
218 /// can be null for reference types.
219 /// </param>
220 /// <returns>
221 /// The zero-based index of the first occurrence of item within the entire ThreadSafeCollection&lt;T&gt;,
222 /// if found; otherwise, –1.
223 /// </returns>
224 public int IndexOf(T item)
225 {
226 lock (this.lockObject)
227 {
228 return list.IndexOf(item);
229 }
230 }
231
232 /// <summary>
233 /// Inserts an element into the ThreadSafeCollection&lt;T&gt; at the specified
234 /// index.
235 /// </summary>
236 /// <param name="index">
237 /// The zero-based index at which item should be inserted.
238 /// </param>
239 /// <param name="item">
240 /// The object to insert. The value can be null for reference types.
241 /// </param>
242 /// <exception cref="ArgumentOutOfRangeException">Index is less than 0.-or-index is greater than ThreadSafeCollection&lt;T&gt;.Count.</exception>
243 public void Insert(int index, T item)
244 {
245 lock (this.lockObject)
246 {
247 list.Insert(index, item);
248 }
249 }
250
251 /// <summary>
252 /// Removes the element at the specified index of the ThreadSafeCollection&lt;T&gt;.
253 /// </summary>
254 /// <param name="index">The zero-based index of the element to remove.</param>
255 /// <exception cref="System.ArgumentOutOfRangeException">Index is less than 0.-or-index is equal to or greater than ThreadSafeCollection&lt;T&gt;.Count.</exception>
256 public void RemoveAt(int index)
257 {
258 lock (this.lockObject)
259 {
260 list.RemoveAt(index);
261 }
262 }
263
264 /// <summary>
265 /// Removes the first occurrence of a specific object from the ThreadSafeCollection&lt;T&gt;.
266 /// </summary>
267 /// <param name="item">
268 /// The object to remove from the ThreadSafeCollection&lt;T&gt;. The value
269 /// can be null for reference types.
270 /// </param>
271 /// <returns>
272 /// true if item is successfully removed; otherwise, false. This method also
273 /// returns false if item was not found in the ThreadSafeCollection&lt;T&gt;.
274 /// </returns>
275 public bool Remove(T item)
276 {
277 lock (this.lockObject)
278 {
279 return list.Remove(item);
280 }
281 }
282
283 /// <summary>
284 /// Returns an enumerator that iterates through the ThreadSafeCollection&lt;T&gt;.
285 /// </summary>
286 /// <remarks>This enumerator is a SNAPSHOT of the collection. Keep this in mind when using this enumerator.</remarks>
287 /// <returns>A ThreadSafeCollection&lt;T&gt;.Enumerator for the ThreadSafeCollection&lt;T&gt;.</returns>
288 IEnumerator<T> IEnumerable<T>.GetEnumerator()
289 {
290 lock (this.lockObject)
291 {
292 return NewEnumerator();
293 }
294 }
295
296 /// <summary>
297 /// Returns an enumerator that iterates through the ThreadSafeCollection&lt;T&gt;.
298 /// </summary>
299 /// <remarks>This enumerator is a SNAPSHOT of the collection. Keep this in mind when using this enumerator.</remarks>
300 /// <returns>A ThreadSafeCollection&lt;T&gt;.Enumerator for the ThreadSafeCollection&lt;T&gt;.</returns>
301 IEnumerator IEnumerable.GetEnumerator()
302 {
303 lock (this.lockObject)
304 {
305 return NewEnumerator();
306 }
307 }
308
309 /// <summary>
310 /// Returns an enumerator that iterates through the ThreadSafeCollection&lt;T&gt;.
311 /// </summary>
312 /// <remarks>This support function exists to satisfy code quality warning CA2000. Otherwise, it would be in-line.</remarks>
313 /// <returns>A ThreadSafeCollection&lt;T&gt;.Enumerator for the ThreadSafeCollection&lt;T&gt;.</returns>
314 private IEnumerator<T> NewEnumerator()
315 {
316 return new ThreadSafeEnumerator(this);
317 }
318
319 /// <summary>
320 /// Provides a SNAPSHOT enumerator of the collection. Keep this in mind when using this enumerator.
321 /// </summary>
322 private class ThreadSafeEnumerator : IEnumerator<T>
323 {
324 /// <summary>
325 /// Snapshot to enumerate.
326 /// </summary>
327 private readonly ThreadSafeCollection<T> collection;
328
329 /// <summary>
330 /// Internal enumerator of the snapshot.
331 /// </summary>
332 private readonly IEnumerator<T> enumerator;
333
334 /// <summary>
335 /// Initializes a new instance of the ThreadSafeEnumerator class, creating a snapshot of the given collection.
336 /// </summary>
337 /// <param name="collection">List to snapshot.</param>
338 public ThreadSafeEnumerator(ThreadSafeCollection<T> collection)
339 {
340 lock (collection.lockObject)
341 {
342 // Make snapshot of passed in collection.
343 this.collection = new ThreadSafeCollection<T>();
344 this.collection.AddRange(collection);
345
346 // Wrapped enumerator.
347 enumerator = this.collection.list.GetEnumerator();
348 }
349 }
350
351 /// <summary>
352 /// Gets the element in the collection at the current position of the enumerator.
353 /// </summary>
354 /// <returns>The element in the collection at the current position of the enumerator.</returns>
355 public T Current
356 {
357 get
358 {
359 lock (this.collection.lockObject)
360 {
361 return enumerator.Current;
362 }
363 }
364 }
365
366 /// <summary>
367 /// Gets the element in the collection at the current position of the enumerator.
368 /// </summary>
369 /// <returns>The element in the collection at the current position of the enumerator.</returns>
370 object IEnumerator.Current
371 {
372 get
373 {
374 lock (this.collection.lockObject)
375 {
376 return enumerator.Current;
377 }
378 }
379 }
380
381 /// <summary>
382 /// Disposes the underlying enumerator. Does not set collection or enumerator to null so calls will still
383 /// proxy to the disposed instance (and throw the proper exception).
384 /// </summary>
385 public void Dispose()
386 {
387 lock (this.collection.lockObject)
388 {
389 enumerator.Dispose();
390 }
391 }
392
393 /// <summary>
394 /// Advances the enumerator to the next element of the collection.
395 /// </summary>
396 /// <returns>
397 /// true if the enumerator was successfully advanced to the next element; false
398 /// if the enumerator has passed the end of the collection.
399 /// </returns>
400 /// <exception cref="System.InvalidOperationException">The collection was modified after the enumerator was created.</exception>
401 public bool MoveNext()
402 {
403 lock (this.collection.lockObject)
404 {
405 return enumerator.MoveNext();
406 }
407 }
408
409 /// <summary>
410 /// Sets the enumerator to its initial position, which is before the first element
411 /// in the collection.
412 /// </summary>
413 /// <exception cref="System.InvalidOperationException">The collection was modified after the enumerator was created.</exception>
414 public void Reset()
415 {
416 lock (this.collection.lockObject)
417 {
418 enumerator.Reset();
419 }
420 }
421 }
422 }
423}
Note: See TracBrowser for help on using the repository browser.