HowTo Asynchronous Worker Process

From Frederick Chapleau Wiki

Jump to: navigation, search

Overview

This is based on the HowTo DesignPattern Singleton article.

After a call to AsyncProcessor.Instance.Start(); the processor will start, and a call to AsyncProcessor.Instance.Queue(theIdToProcess); will queue the request that is, in that context, a simple GUID.

Source

    public class AsyncProcessor
    {
 
        #region Singleton
 
        /// <summary>
        /// Private static variable representing the single intance of the class
        /// </summary>
        private static AsyncProcessor _instance;
 
        /// <summary>
        /// This constructor is private, so, the only class that can create it, is... me.
        /// </summary>
        private AsyncProcessor()
        {
        }
 
        /// <summary>
        /// The Instance public property is the accessor to the single instance of the
        /// class. This is static because the constructor is private, so it's the only way to
        /// access a property 
        /// </summary>
        public static AsyncProcessor Instance
        {
            get
            {
 
                // if the instance is not yet created,
                if (_instance == null)
                {
                    // We create the only intance of our self
                    _instance = new AsyncProcessor();
                    _instance._processingObjects = new Queue<Guid>();
                }
 
                // and we return the only instance
                return _instance;
            }
        }
 
        #endregion
 
        private Thread _asyncProcessing;
        private Queue<Guid> _processingObjects;
 
        public void Start()
        {
            ThreadStart ts = new ThreadStart(AsyncStart);
            _asyncProcessing = new Thread(ts);
            _asyncProcessing.Name = "Asynchronous Processing";
            _asyncProcessing.IsBackground = true;
            _asyncProcessing.Start();
        }
 
        public void AsyncStart()
        {
            while (true)
            {
                bool processed = false;
                Guid currentId = Guid.Empty;
 
                // Here we lock the queue to check if there is something to process
                Monitor.Enter(_asyncProcessing);
                if (_processingObjects.Count > 0)
                {
                    // Here we just peek the next object
                    // The object will remain in the queue until a dequeue is done.
                    currentId = _processingObjects.Peek();
                }
                Monitor.Exit(_asyncProcessing);
 
                if (currentId != Guid.Empty)
                {
                    try
                    {
                        // ***********
                        // TODO: Implement the logic to process the ID
                        // ***********
 
 
                        // process the current id
                        processed = true;
 
                        // Now that the process is done, we remove the id from the queue
                        Monitor.Enter(_asyncProcessing);
                        _processingObjects.Dequeue();
                        Monitor.Exit(_asyncProcessing);
                    }
                    catch
                    {
                        // Error Handling, here we just sleep & retry the same object (the peek didn't release it)
                    }
 
                }
 
                // if something was processed we wait less, just to throttle processing
                // else we wait longer.
                if(processed)
                    Thread.Sleep(100);
                else
                    Thread.Sleep(1000);
            }
        }
 
        public void Queue(Guid id)
        {
            Monitor.Enter(_processingObjects);
            _processingObjects.Enqueue(id);
            Monitor.Exit(_processingObjects);
        }
    }
Personal tools