andrew4582

ThrottledQueue<T>

Jun 27th, 2012
150
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 3.01 KB | None | 0 0
  1.     /// <summary>
  2.     /// Throttles the processing of a collection of items, based on how many threads are specified
  3.     /// Substitute for when PLinq AsParallel() doesn't work for whatever reasons
  4.     /// <example>
  5.     /// new ThrottledQueue<int>(2,Enumerable.Range(1,100),(i) => Console.WriteLine(i + " " + Thread.CurrentThread.ManagedThreadId))
  6.     /// .Wait();
  7.     /// </example>
  8.     /// </summary>
  9.     /// <typeparam name="T"></typeparam>
  10.     public class ThrottledQueue<T>:IDisposable {
  11.  
  12.         readonly ConcurrentQueue<T> _queue;
  13.         readonly int _numberOfThreads;
  14.         readonly CountdownEvent _waitCountdown;
  15.         readonly CountdownEvent _startCountdown;
  16.         readonly ManualResetEvent _startEvent;
  17.         volatile bool _cancelled;
  18.         Action<T> _processAction;
  19.        
  20.         public int NumberOfThreads {
  21.             get { return _numberOfThreads; }
  22.         }
  23.  
  24.         public bool IsCancelled {
  25.             get { return _cancelled; }
  26.         }
  27.  
  28.         public void Cancel() {
  29.             if(_cancelled)
  30.                 throw new InvalidOperationException("Already cancelled");
  31.             _cancelled = true;
  32.         }
  33.        
  34.         public void Wait() {
  35.             _waitCountdown.Wait();
  36.         }
  37.  
  38.         public ThrottledQueue(int numberOfThreads,IEnumerable<T> collection,Action<T> processAction) {
  39.             //TODO: Argument
  40.  
  41.             _numberOfThreads = numberOfThreads;
  42.             _processAction = processAction;
  43.             _queue = new ConcurrentQueue<T>(collection);
  44.             _waitCountdown = new CountdownEvent(collection.Count());
  45.             _startCountdown = new CountdownEvent(numberOfThreads);
  46.             _startEvent = new ManualResetEvent(false);
  47.  
  48.             for(int i = 0;i < numberOfThreads;i++)
  49.                 ThreadPool.QueueUserWorkItem(RunningWorker,i);
  50.  
  51.             //wait until all threads are started
  52.             _startCountdown.Wait();
  53.            
  54.             //after all threads are started then signal them to start processing the queue
  55.             _startEvent.Set();
  56.         }
  57.  
  58.         void RunningWorker(object id) {
  59.  
  60.             int workerid = (int)id;
  61.              
  62.             Console.WriteLine(string.Format("Worker #{0:N0} started",workerid));
  63.            
  64.             _startCountdown.Signal();
  65.             _startEvent.WaitOne();
  66.  
  67.             while(!_cancelled) {
  68.                 T item;
  69.                 if(_queue.TryDequeue(out item)) {
  70.                     bool quit = false;
  71.                     try {
  72.                         _processAction(item);
  73.                     }
  74.                     catch { }
  75.                     finally {
  76.                         if(_waitCountdown.Signal())
  77.                             quit = true;
  78.                     }
  79.                     if(quit)
  80.                         return;
  81.                 }
  82.                 else
  83.                     Thread.Sleep(10);
  84.             }
  85.         }
  86.  
  87.         public void Dispose() {
  88.             if(!IsCancelled)
  89.                 Cancel();
  90.         }
  91.     }
Advertisement
Add Comment
Please, Sign In to add comment