Click here to Skip to main content
15,893,564 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.8K   862   139  
An introduction and proof of concept code for the idea of declarative multi threading in C#.
using System;
using System.Runtime.Remoting.Proxies;
using System.Threading;
using System.Runtime.Remoting;
using System.Security.Permissions;

namespace ThreadBound
{
    /// <summary>
    /// This attribute binds a class to a thread. Every method call will be executed within the same thread. Method
    /// calls from other threads will be transported to the classes thread.
    /// </summary>
    /// <remarks>
    /// If the attribute is used with the ThreadBinding CurrentContext the class must be instantiated from within
    /// a SynchronisationContext. Normally this is WPF- or Forms-GUI-threads. If the current context is null an
    /// exception will be thrown.
    /// </remarks>
    [AttributeUsage(AttributeTargets.Class)]
    [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
    public class ThreadBoundAttribute : ProxyAttribute
    {
        /// <summary>
        /// Enummeration of contexts that can be used to bind a class instance to:
        /// <list type="bullet">
        /// <item>
        ///     <term>CurrentContext</term>
        ///     <description>Use the current context. This type is only valid if the class gets instanciated within a WPF or WinForms GUI context.</description>
        /// </item>
        /// <item>
        ///     <term>WorkerContext</term>
        ///     <description>Creates a dedicated worker thread for each instance of the class.</description>
        /// </item>
        /// <item>
        ///     <term>PoolContext</term>
        ///     <description>Uses the thread pool to execute the methods of the class. The different methods may be executed on different thread pool threads.</description>
        /// </item>
        /// </list>
        /// </summary>
        public enum ThreadBinding {CurrentContext, WorkerContext, PoolContext};

        /// <summary>
        /// The thread binding set via the first parameter of the attribute.
        /// </summary>
        private ThreadBinding DesiredBindingType;

        /// <summary>
        /// c'tor: Defaulting to binding the current instance to the current context
        /// </summary>
        public ThreadBoundAttribute() :
            this(ThreadBinding.CurrentContext)
        {
            //-- The default is to use an existing context.
        }

        /// <summary>
        /// c'tor: Binds all instances of a class marked with this attribute to the selected context.
        /// </summary>
        /// <param name="bindingType">A binding type describe within the <see cref="ThreadBoundAttribute.ThreadBinding"/>ThreadBinding</see> enumeration.</param>
        public ThreadBoundAttribute(ThreadBinding bindingType) :
            base()
        {
            DesiredBindingType = bindingType;
        }

        /// <summary>
        /// This method is called by the framework if a class derived from ContextBoundObject and taged with a proxy
        /// attribute is instantiated.
        /// </summary>
        /// <param name="serverType">Type the framework is trying to create an instance of.</param>
        /// <returns>Returns the new instance casted to a MarshalByRefObject reference.</returns>
        public override MarshalByRefObject CreateInstance(Type serverType)
        {
            SynchronizationContext ExecContext=null;

            if (!serverType.IsContextful)
                throw new ThreadBoundException("Type must be derived from ContextBoundObject or ThreadBoundObject.");

            //-- Instanciate a cleass that implements the SynchronisationContext to use
            switch (DesiredBindingType)
            {
                case ThreadBinding.CurrentContext:
                    ExecContext = SynchronizationContext.Current;
                    if (ExecContext == null)
                        throw new ThreadBoundException("Can't use current context, because there is no current context set.");
                    break;
                case ThreadBinding.WorkerContext:
                    if (!typeof(IDisposable).IsAssignableFrom(serverType))
                        throw new ThreadBoundException("Worker instances must im plement IDisposable.");

                    ExecContext = new WorkerSynchronizationContext(new Worker("ThreadBoundContextWorker"));
                    break;
                case ThreadBinding.PoolContext:
                    ExecContext = new PoolSynchronizationContext();
                    break;
            }

            ThreadBoundProxy newProxy = new ThreadBoundProxy(serverType, ExecContext);
            return (MarshalByRefObject)newProxy.GetTransparentProxy();
        }
    }
}

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