Click here to Skip to main content
15,891,704 members
Articles / General Programming / Threads

Declarative multithreading

Rate me:
Please Sign up or sign in to vote.
4.94/5 (39 votes)
13 Mar 2012CDDL19 min read 58.5K   862   139  
An introduction and proof of concept code for the idea of declarative multi threading in C#.
using System;
using System.Threading;

namespace ThreadBound
{
    /// <summary>
    /// Base class for all (synchronous and asynchronous) WorkQueueItems.
    /// Each WorkQueueItem represents an action to execute within an other thread.
    /// </summary>
    internal abstract class WorkQueueItem
    {
        /// <summary>
        /// Reference to a delegate that will be called if the QueueItem is invoked.
        /// </summary>
        private SendOrPostCallback Callback;

        /// <summary>
        /// A reference that should be passed to the state-parameter of the Invoke method call.
        /// </summary>
        private Object State;

        /// <summary>
        /// C'tor
        /// </summary>
        /// <param name="callback">Reference to a delegate that will be called if the QueueItem is invoked.</param>
        /// <param name="state">A reference that should be passed to the state-parameter of the Invoke method call.</param>
        public WorkQueueItem(SendOrPostCallback callback, Object state)
        {
            Callback = callback;
            State = state;
        }

        /// <summary>
        /// Invokes the callback passed to the c'tor with the set state.
        /// </summary>
        public virtual void Invoke()
        {
            Callback.Invoke(State);
        }
    }

    /// <summary>
    /// WorkQueueItem for synchronous method calls
    /// </summary>
    internal class SyncWorkQueueItem :
        WorkQueueItem
    {
        /// <summary>
        /// A thread static done event. Because every thread can only execute one function at
        /// a time. One global done event per thread is sufficient.
        /// </summary>
        [ThreadStatic]
        private static AutoResetEvent GlobalDoneEvent;

        /// <summary>
        /// Done event for this QueueItem. Will be set to the global Done event.
        /// </summary>
        private AutoResetEvent DoneEvent;

        /// <summary>
        /// If an exception is raised within Invoke the exception is stored within
        /// this variable. It can be rethrown by using RethrowException.
        /// </summary>
        private volatile Exception LastException;

        /// <summary>
        /// C'tor
        /// </summary>
        /// <param name="callback">Reference to a delegate that will be called if the QueueItem is invoked.</param>
        /// <param name="state">A reference that should be passed to the state-parameter of the Invoke method call.</param>
        public SyncWorkQueueItem(SendOrPostCallback callback, Object state) :
            base(callback, state)
        {
            //-- Because every thread waits until the current synchronous call is done,
            //   one done event per thread is enough. It is created and cached.
            //   This simple locking is sufficient because there is only one thread
            //   using this "singleton".
            if (GlobalDoneEvent == null)
                GlobalDoneEvent = new AutoResetEvent(false);

            DoneEvent = GlobalDoneEvent;
        }

        /// <summary>
        /// Waits for the current invokation to complete.
        /// </summary>
        public void Join()
        {
            DoneEvent.WaitOne();
        }

        /// <summary>
        /// Invokes the method set within the c'tor.
        /// </summary>
        /// <seealso cref="WorkQueueItem.WorkQueueItem"/>
        public override void Invoke()
        {
            try
            {
                base.Invoke();
            }
            catch (Exception allExceptions)
            {
                LastException = allExceptions;
            }

            //-- Wenn ein Done-Event mit diesem Eintrag verknüpft ist, dieses jetzt setzen
            DoneEvent.Set();
        }

        /// <summary>
        /// Allows the usage of SyncWorkQueueItem within a PoolSynchronizationContext wich requres a parameter.
        /// </summary>
        /// <param name="state">Dummy-parameter to use this class with WaitCallback.</param>
        public void Invoke(Object state)
        {
            Invoke();
        }

        /// <summary>
        /// If an exception occured within Invoke this methods rethrows the exception. If no exception
        /// occured the method will do nothing.
        /// </summary>
        public void RethrowException()
        {
            if (LastException != null)
                throw LastException;
        }
    };

    /// <summary>
    /// WorkQueueItem for asynchronous calls.
    /// </summary>
    /// <remarks>Implements nothing more than the base class. Only a thin wraper because asynchronous calls do not need any synchronization.</remarks>
    internal class AsyncWorkQueueItem :
        WorkQueueItem
    {
        /// <summary>
        /// C'tor
        /// </summary>
        /// <param name="callback">Reference to a delegate that will be called if the QueueItem is invoked.</param>
        /// <param name="state">A reference that should be passed to the state-parameter of the Invoke method call.</param>
        public AsyncWorkQueueItem(SendOrPostCallback callback, Object state) :
            base(callback, state)
        {
        }
    };
}

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 Common Development and Distribution License (CDDL)


Written By
Systems Engineer
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions