Click here to Skip to main content
15,886,778 members
Articles / Programming Languages / C#

Proactor Pattern

Rate me:
Please Sign up or sign in to vote.
4.55/5 (18 votes)
2 Feb 2009GPL33 min read 64.8K   1K   71  
Proactor Pattern is an asynchronous event handling pattern.
#region License
/* Copyright (c) 2008 Hamed Ebrahimmalek
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to 
 * deal in the Software without restriction, including without limitation the 
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 
 * sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software. 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
 * THE SOFTWARE.
 */
#endregion

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Threading;
using Operational.Interfaces;
using System.Diagnostics;

namespace EventHandler
{
    #region Copyright Hamed Ebrahimmalek, 2008
    // Hamed Ebrahimmalek
    //
    // Project              : Proactor
    // Module               : Dispatcher
    // File name            : Dispatcher.cs
    // Revision             : 0.1
    // Creation Date        : 28-04-2008
    // First Author         : Hamed Ebrahimmalek
    //
    // Description          : 
    //
    #endregion

    public sealed class Dispatcher
    {
        public enum Priority { VeryHigh = 0, High, Normal, Low, VeryLow, MAX };

        /// <summary>
        /// contains all the registered items
        /// </summary>
        private Hashtable _registry = new Hashtable();

        /// <summary>
        /// counts the created registry id
        /// </summary>
        private int _registeryID = 0;

        /// <summary>
        /// The disptachers thread
        /// </summary>
        private Thread _dispachThread = null;

        /// <summary>
        /// To hold and signal the running thread
        /// </summary>
        private Semaphore _autoResetEvent = new Semaphore( 0, int.MaxValue );

        /// <summary>
        /// The dispatchers instance
        /// </summary>
        static Dispatcher _instance = null;

        /// <summary>
        /// the dispatchers queue
        /// </summary>
        private PriorityQueue _queue = new PriorityQueue( (UInt32)Priority.MAX );

        /// <summary>
        /// This is used to lock the dispatchers instance
        /// </summary>
        private static readonly object _instanceLock = new object();

        /// <summary>
        /// Constructor, no default constructor allowed
        /// This is a Singleton class.
        /// </summary>
        private Dispatcher()
        {

        }

        /// <summary>
        /// Initializes the dispatcher
        /// </summary>
        public void Initialize()
        {
            _dispachThread = new Thread(Dispatch);
        }
        
        /// <summary>
        /// Starts the dispatcher
        /// </summary>
        public void Start()
        {
            // start the disptachers thread
            _dispachThread.Start();
        }

        /// <summary>
        /// Stops the dispatcher
        /// </summary>
        public void Stop()
        {
            // join the thread
            _dispachThread.Join();
        }

        /// <summary>
        /// Terminates the dispatcher
        /// </summary>
        public void Terminate( )
        {
            _autoResetEvent.Release();
        }

        /// <summary>
        /// Dispatches the events to the dispatchable items
        /// </summary>
        private void Dispatch()
        {
            // thread must be running.
            while (_dispachThread.ThreadState == System.Threading.ThreadState.Running)
            {
                // wait for signal
                _autoResetEvent.WaitOne();
                
                // the queue should have at least one queue item available
                if( _queue.Count >= 1 )
                {
                    QueueItem queueItem = null;
                    
                    // We're going to dequeue an QueueItem from the dispatchers queue
                    lock (_queue)
                    {
                        // get a queue item
                        queueItem = _queue.Dequeue() as QueueItem;
                        
                        // this must be valid!
                        Debug.Assert(queueItem != null);

                        // get the dispatchable item 
                        IDispatchable dispItem = queueItem.DISP_ITEM;

                        // handle the event of the dispatchable item
                        dispItem.HandleEvent(queueItem.IEVENT);
                    }
                }
            }
        }

        /// <summary>
        /// Registers the dispatchable items
        /// </summary>
        /// <param name="dispItem">the dispatchable items to register</param>
        /// <returns>the registered dispatchable id</returns>
        public int Register(IDispatchable dispItem)
        {
            // When registering a dispatchable item, this must be valid!
            Debug.Assert(dispItem != null);

            // one execution at a time
            lock (_registry)
            {
                // insert the item to the registery
                _registry.Add(_registeryID, dispItem);
                
                // give the dispatchabe item its ID
                dispItem.DISPATCHABLE_ID = _registeryID;

                // count the id up
                _registeryID++;
            }

            // return the original ID
            return dispItem.DISPATCHABLE_ID;
        }

        /// <summary>
        /// Enqueues the IEvent to the dispatchable item
        /// </summary>
        /// <param name="iDispID">the dispatchable id to enqueue the event to</param>
        /// <param name="ievent">the event to dispatch</param>
        public void Enqueue( int dispatchableID, IEvent ievent, Priority priority )
        {
            Debug.Assert(ievent != null);

            IDispatchable dispItem = _registry[dispatchableID] as IDispatchable;
            Debug.Assert(dispItem != null);
            
            // create a new queue item
            QueueItem queueItem = new QueueItem( dispItem, ievent );
            
            // lock the enqueue, since the enqueue could take place from
            // different threads.
            lock (_queue)
            {
                _queue.Enqueue(queueItem, Convert.ToUInt32( priority ) );                   
            }
            // Tell the thread that we have inserted a new item
            _autoResetEvent.Release();
        }

        /// <summary>
        /// This method will return the Dispatchers instance
        /// This is a Singleton pattern.
        /// </summary>
        public static Dispatcher GetInstance
        {
            get
            {
                lock (_instanceLock)
                {
                    // if the instance exists, then return the
                    // already created disptacher
                    if (_instance == null)
                    {
                        // first time for the singleton
                        _instance = new Dispatcher();
                    }
                    return _instance;
                }
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer
Netherlands Netherlands
I'm a C++ and C# .Net software engineer.

Comments and Discussions