andrew4582

AsyncWorkerCollection

Jul 14th, 2012
162
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.76 KB | None | 0 0
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7.  
  8. namespace  Core {
  9.  
  10.     /// <summary>
  11.     /// A class to process a collection of items in a threaded controlled manner
  12.     /// </summary>
  13.     /// <typeparam name="T"></typeparam>
  14.     [DebuggerDisplay("Count = {Count}, Workers = {_numberOfWorkers}, Type = {typeof(T)}")]
  15.     public class AsyncWorkerCollection<T>:IDisposable{
  16.  
  17.         readonly int _numberOfWorkers;
  18.         readonly Action<T> _processAction;
  19.         readonly BlockingCollection<T> _collection;
  20.         readonly CancellationTokenSource _cancelSource;
  21.         readonly Task[] _workerTasks;
  22.  
  23.         /// <summary>
  24.         /// ctor
  25.         /// </summary>
  26.         /// <param name="numberOfWorkers">The number of worker threads to process the collection</param>
  27.         /// <param name="processAction">The action delegate to process each item</param>
  28.         public AsyncWorkerCollection(int numberOfWorkers,Action<T> processAction) {
  29.  
  30.             Argument.IsNotNegativeOrZero(numberOfWorkers,"numberOfThreads");
  31.             Argument.IsNotNull(processAction,"processAction");
  32.            
  33.             _numberOfWorkers = numberOfWorkers;
  34.             _processAction = processAction;
  35.             _cancelSource = new CancellationTokenSource();
  36.             _collection = new BlockingCollection<T>();
  37.             _workerTasks = new Task[_numberOfWorkers];
  38.  
  39.             StartWorkers();
  40.         }
  41.  
  42.         /// <summary>
  43.         /// Attempts to add the specified item to the System.Collections.Concurrent.BlockingCollection<T>.
  44.         /// </summary>
  45.         /// <param name="item">The item to be added to the collection and processed</param>
  46.         /// <returns>True if item could be added; otherwise false because <see cref="IsAddingCompleted"/> is true.</returns>
  47.         public bool Add(T item) {
  48.  
  49.             this.EnsureNotDisposed();
  50.             if(_collection.TryAdd(item)) {
  51.                 return true;
  52.             }
  53.             return false;
  54.         }
  55.         /// <summary>
  56.         /// Add the specified items to the System.Collections.Concurrent.BlockingCollection<T>.
  57.         /// </summary>
  58.         public void AddRange(IEnumerable<T> items) {
  59.  
  60.             this.EnsureNotDisposed();
  61.  
  62.             foreach(T item in items)
  63.                 this.Add(item);
  64.         }
  65.  
  66.         public int Count {
  67.             get {
  68.                 return _collection.Count;
  69.             }
  70.         }
  71.  
  72.         /// <summary>
  73.         ///  Gets whether this System.Collections.Concurrent.BlockingCollection<T> has been marked as complete for adding.
  74.         /// </summary>
  75.         public bool IsAddingCompleted {
  76.             get {
  77.                 this.EnsureNotDisposed();
  78.                 return _collection.IsAddingCompleted;
  79.             }
  80.         }
  81.  
  82.         /// <summary>
  83.         /// Waits for all of the provided System.Threading.Tasks.Task objects to complete
  84.         /// </summary>
  85.         public void Wait() {
  86.             this.CompleteAdding();
  87.             Task.WaitAll(_workerTasks,_cancelSource.Token);
  88.         }
  89.        
  90.         /// <summary>
  91.         /// Waits for all of the provided System.Threading.Tasks.Task objects to complete
  92.         /// </summary>
  93.         /// <param name="timeout">A System.TimeSpan that represents the number of milliseconds to wait, or a System.TimeSpan that represents -1 milliseconds to wait indefinitely.</param>
  94.         /// <returns>true if the System.Threading.Tasks.Task completed execution within the allotted time; otherwise, false.</returns>
  95.         public bool Wait(TimeSpan timeout) {
  96.             Argument.IsNotNull(timeout,"timeout");
  97.             this.CompleteAdding();
  98.             return Task.WaitAll(_workerTasks,(int)timeout.TotalMilliseconds,_cancelSource.Token);
  99.         }
  100.         /// <summary>
  101.         ///
  102.         /// </summary>
  103.         /// <param name="milliseconds">The number of milliseconds to wait, or System.Threading.Timeout.Infinite (-1) to wait indefinitely.</param>
  104.         /// <returns>true if the System.Threading.Tasks.Task completed execution within the allotted time; otherwise, false.</returns>
  105.         public bool Wait(int milliseconds) {
  106.             Argument.IsNotOutOfRange(milliseconds,-1,int.MaxValue,"milliseconds");
  107.             this.CompleteAdding();
  108.             return Task.WaitAll(_workerTasks,milliseconds,_cancelSource.Token);
  109.         }
  110.  
  111.         /// <summary>
  112.         ///  Marks the collection as not accepting any more additions.
  113.         /// </summary>
  114.         public void CompleteAdding() {
  115.  
  116.             this.EnsureNotDisposed();
  117.  
  118.             if(!_collection.IsAddingCompleted)
  119.                 _collection.CompleteAdding();
  120.         }
  121.         /// <summary>
  122.         /// True if collection has been cancelled
  123.         /// </summary>
  124.         public bool IsCancellationRequested {
  125.             get {
  126.                 this.EnsureNotDisposed();
  127.                 return _cancelSource.IsCancellationRequested;
  128.             }
  129.         }
  130.  
  131.         /// <summary>
  132.         /// Communicates a request for cancellation.
  133.         /// </summary>
  134.         public void Cancel() {
  135.             this.EnsureNotDisposed();
  136.  
  137.             if(!_cancelSource.IsCancellationRequested)
  138.                 _cancelSource.Cancel();
  139.         }
  140.  
  141.         /// <summary>
  142.         /// Starts the worker threads on ctor
  143.         /// </summary>
  144.         void StartWorkers() {
  145.             this.EnsureNotDisposed();
  146.  
  147.             for(int i = 0;i < _numberOfWorkers;i++) {
  148.                
  149.                 _workerTasks[i] = Task.Factory.StartNew((state) =>
  150.                 {
  151.                     Tuple<int> parms = (Tuple<int>)state;
  152.                     int workerId = parms.Item1;
  153.                    
  154.                     foreach(T item in _collection.GetConsumingEnumerable(_cancelSource.Token)) {
  155.                         try {
  156.                             //process action on each item
  157.                             _processAction(item);
  158.                         }
  159.                         catch { }
  160.                     }
  161.  
  162.                 },Tuple.Create<int>(i));
  163.  
  164.             }
  165.         }
  166.  
  167.         #region IDisposable Pattern
  168.  
  169.         protected bool IsDisposed { get; private set; }
  170.  
  171.         [System.Diagnostics.DebuggerStepThrough]
  172.         protected void EnsureNotDisposed() {
  173.             if(IsDisposed)
  174.                 throw new ObjectDisposedException(GetType().Name);
  175.         }
  176.  
  177.         [System.Diagnostics.DebuggerStepThrough]
  178.         public void Dispose() {
  179.             if(IsDisposed)
  180.                 throw new ObjectDisposedException(this.GetType().Name);
  181.             try {
  182.                 this.Dispose(true);
  183.             }
  184.             finally {
  185.                 GC.SuppressFinalize(this);
  186.             }
  187.         }
  188.  
  189.         [System.Diagnostics.DebuggerStepThrough]
  190.         protected virtual void Dispose(bool disposing) {
  191.             if(IsDisposed)
  192.                 return;
  193.             if(!disposing)
  194.                 return;
  195.  
  196.             try {
  197.                 try {
  198.  
  199.                     if(!this._collection.IsAddingCompleted) {
  200.                         this._collection.CompleteAdding();
  201.                     }
  202.  
  203.                 }
  204.                 finally {
  205.  
  206.                     try {
  207.                         this._collection.Dispose();
  208.                     }
  209.                     finally {
  210.  
  211.                         try {
  212.                             _workerTasks.ForEach(t => t.Dispose());
  213.                         }
  214.                         finally {
  215.                             this._cancelSource.Dispose();
  216.                         }
  217.                     }
  218.                 }
  219.             }
  220.             finally {
  221.                 this.IsDisposed = true;
  222.             }
  223.         }
  224.         #endregion
  225.     }
  226. }
Advertisement
Add Comment
Please, Sign In to add comment