andrew4582

OutputQueue

Aug 21st, 2010
229
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.32 KB | None | 0 0
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Diagnostics;
  6. using System.Threading;
  7. using System.Threading.Parallel;
  8.  
  9. namespace DbMon.NET {
  10.  
  11.     public partial class OutputQueue<T>:Component {
  12.         /// <summary>
  13.         /// Max size of queue
  14.         /// </summary>
  15.         const int MAX_QUEUE_SIZE = 5000;
  16.  
  17.         //internal queue
  18.         readonly ConcurrentQueue<T> _outputQueue = new ConcurrentQueue<T>();
  19.         readonly object _syncRoot = new object();
  20.  
  21.         AsyncOperation _outputOperation { get; set; }
  22.         AutoResetEvent _stopResetEvent = new AutoResetEvent(false);
  23.  
  24.         long _enabled = 1;
  25.         long _state;
  26.  
  27.         public Action<OutputQueue<T>,OutputArgs<T>> Output;
  28.  
  29.         #region ctr & Properties
  30.         /// <summary>
  31.         /// Gets or Sets the maximum queue size, when the maximum is reached pause notifications are send to the DebugOutputQueue subscribers
  32.         /// </summary>
  33.         public int MaxQueueSize { get; set; }
  34.  
  35.         public object SyncRoot {
  36.             get {
  37.                 return _syncRoot;
  38.             }
  39.         }
  40.         public bool IsEnabled {
  41.             get {
  42.                 return ParallelTask.GetRefBool(ref _enabled);
  43.             }
  44.             set {
  45.                 ParallelTask.SetRefBool(value,ref _enabled);
  46.             }
  47.         }
  48.         public OutputQueueState State {
  49.             get {
  50.                 return (OutputQueueState)Interlocked.Read(ref _state);
  51.             }
  52.             set {
  53.                 Interlocked.Exchange(ref _state,(long)value);
  54.             }
  55.         }
  56.  
  57.         public bool IsStarted {
  58.             get {
  59.                 if(State == OutputQueueState.Started)
  60.                     return true;
  61.                 return false;
  62.             }
  63.  
  64.         }
  65.         public bool IsPaused {
  66.             get {
  67.                 if(State == OutputQueueState.Paused)
  68.                     return true;
  69.                 return false;
  70.             }
  71.  
  72.         }
  73.         public bool IsStoppedOrPending {
  74.             get {
  75.                 if(State == OutputQueueState.Stopped || State == OutputQueueState.StopPending)
  76.                     return true;
  77.                 return false;
  78.             }
  79.  
  80.         }
  81.         public OutputQueue() {
  82.             MaxQueueSize = MAX_QUEUE_SIZE;
  83.             State = OutputQueueState.None;
  84.             InitializeComponent();
  85.         }
  86.         public OutputQueue(IContainer container)
  87.             : this() {
  88.             container.Add(this);
  89.         }
  90.         #endregion
  91.  
  92.         #region Stop, Pause, & Resume
  93.         volatile bool IsPurging;
  94.  
  95.         public bool CanStart(bool throwIfFalse) {
  96.             try {
  97.                 if(IsStarted || State == OutputQueueState.StartPending)
  98.                     throw new ArgumentException("Alread started");
  99.                 if(State == OutputQueueState.StopPending)
  100.                     throw new ArgumentException("Stop pending");
  101.  
  102.                 return true;
  103.             }
  104.             catch {
  105.                 if(throwIfFalse)
  106.                     throw;
  107.                 return false;
  108.             }
  109.         }
  110.         public bool CanStop(bool throwIfFalse) {
  111.             try {
  112.                 if(IsStoppedOrPending)
  113.                     throw new ArgumentException("Already stopped");
  114.                 return true;
  115.             }
  116.             catch {
  117.                 if(throwIfFalse)
  118.                     throw;
  119.                 return false;
  120.             }
  121.         }
  122.         public bool CanPause(bool throwIfFalse) {
  123.             try {
  124.                 if(IsPaused)
  125.                     throw new ArgumentException("Already paused");
  126.                 if(!IsStarted)
  127.                     throw new ArgumentException("Not started");
  128.                 if(State == OutputQueueState.StartPending)
  129.                     throw new ArgumentException("Not started yet");
  130.                 if(IsStoppedOrPending)
  131.                     throw new ArgumentException("Already stopped or is stop pending");
  132.                 return true;
  133.             }
  134.             catch {
  135.                 if(throwIfFalse)
  136.                     throw;
  137.                 return false;
  138.             }
  139.         }
  140.         public bool CanResume(bool throwIfFalse) {
  141.             try {
  142.                 if(!IsPaused)
  143.                     throw new ArgumentException("Not paused");
  144.                 if(!IsStarted)
  145.                     throw new ArgumentException("Not started");
  146.                 if(State == OutputQueueState.StartPending)
  147.                     throw new ArgumentException("Not started yet");
  148.                 if(IsStoppedOrPending)
  149.                     throw new ArgumentException("Already stopped or is stop pending");
  150.                 return true;
  151.             }
  152.             catch {
  153.                 if(throwIfFalse)
  154.                     throw;
  155.                 return false;
  156.             }
  157.         }
  158.  
  159.         public void Stop() {
  160.             Stop(false);
  161.         }
  162.         public void Stop(bool waitOnStopped) {
  163.             if(!CanStop(true))
  164.                 return;
  165.  
  166.             State = OutputQueueState.StopPending;
  167.             if(waitOnStopped) {
  168.                 _stopResetEvent.WaitOne();
  169.             }
  170.         }
  171.         public void Pause() {
  172.             if(!CanPause(true))
  173.                 return;
  174.             State = OutputQueueState.Paused;
  175.         }
  176.         public void Resume() {
  177.             if(!CanResume(true))
  178.                 return;
  179.             State = OutputQueueState.Started;
  180.         }
  181.         #endregion
  182.  
  183.         public void Start() {
  184.             if(!CanStart(true))
  185.                 return;
  186.             State = OutputQueueState.StartPending;
  187.  
  188.             _outputOperation = AsyncOperationManager.CreateOperation(null);
  189.  
  190.             ThreadPool.QueueUserWorkItem((s) => {
  191.                 runningThread();
  192.             });
  193.         }
  194.         public void EnqueueOutput(T item) {
  195.             _outputQueue.Enqueue(item);
  196.         }
  197.         public void EnqueueOutput(T[] items) {
  198.             foreach(var item in items) {
  199.                 _outputQueue.Enqueue(item);
  200.             }
  201.         }
  202.         public void PurgeAll() {
  203.  
  204.             try {
  205.                 IsPurging = true;
  206.  
  207.                 lock(this.SyncRoot) {
  208.                     while(_outputQueue.Count > 0) {
  209.                         try {
  210.                             T qitem = default(T);
  211.                             if(!_outputQueue.TryDequeue(out qitem))
  212.                                 break;
  213.                         }
  214.                         catch { }
  215.                     }
  216.                 }
  217.             }
  218.             finally {
  219.                 IsPurging = false;
  220.             }
  221.         }
  222.  
  223.         void runningThread() {
  224.  
  225.             State = OutputQueueState.Started;
  226.             _stopResetEvent.Reset();
  227.  
  228.             try {
  229.                 while(!IsStoppedOrPending) {
  230.                     try {
  231.                         if(IsPurging) {
  232.                             Thread.Sleep(10);
  233.                             continue;
  234.                         }
  235.  
  236.                         if(IsPaused) {
  237.                             SleepSpin(200);
  238.                             continue;
  239.                         }
  240.                         //dequeue and broadcast items
  241.                         dequeueQueue();
  242.                     }
  243.                     catch(Exception err) {
  244.                         Trace.WriteLine("ERROR: runningThread() -> dequeueQueue() -> " + err.ToString());
  245.                         SleepSpin(500);
  246.                     }
  247.                 }
  248.             }
  249.             finally {
  250.                 State = OutputQueueState.Stopped;
  251.                 _stopResetEvent.Set();
  252.             }
  253.         }
  254.  
  255.         void dequeueQueue() {
  256.             if(!IsEnabled)
  257.                 return;
  258.  
  259.             List<T> list = new List<T>();
  260.             try {
  261.  
  262.                 while(_outputQueue.Count > 0 && list.Count < this.MaxQueueSize) {
  263.  
  264.                     if(IsPurging) {
  265.                         list.Clear();
  266.                         return;
  267.                     }
  268.  
  269.                     if(IsStoppedOrPending)
  270.                         return;
  271.  
  272.                     T qitem = default(T);
  273.  
  274.                     if(_outputQueue.TryDequeue(out qitem))
  275.                         list.Add(qitem);
  276.  
  277.                 }
  278.  
  279.             }
  280.             finally {
  281.  
  282.                 if(list.Count > 0)
  283.                     OnOutput(new OutputArgs<T>(list.ToArray()));
  284.             }
  285.             Thread.Sleep(1);
  286.         }
  287.         protected void OnOutput(OutputArgs<T> args) {
  288.             if(IsPurging)
  289.                 return;
  290.  
  291.             if(Output != null)
  292.                 Output(this,args);
  293.         }
  294.         protected void SleepSpin(int millisecondsTimeout) {
  295.             int spinby = 10;
  296.             int iterations = (millisecondsTimeout / spinby);
  297.             for(int i = 0;i < iterations;i++) {
  298.                 if(IsStoppedOrPending)
  299.                     return;
  300.                 Thread.Sleep(spinby);
  301.             }
  302.         }
  303.     }
  304.     public class OutputArgs<T>:EventArgs {
  305.         public T[] Items { get; set; }
  306.         public OutputArgs(T[] items) {
  307.             this.Items = items;
  308.         }
  309.     }
  310.     public enum OutputQueueState:long {
  311.         None,
  312.         StartPending,
  313.         Started,
  314.         StopPending,
  315.         Stopped,
  316.         Paused
  317.     }
  318. }
Advertisement
Add Comment
Please, Sign In to add comment