Naz-Tek Services, Inc.

Writing Software To Provide Strategic Advantage

Home     Development Guidelines     Design Patterns     Knowledgebase     Trainingbase     Blog Feed     Events     Tools     About Us     Contact Us      
Memory Management     Event Handling     Multi-Threading     Serialization      
Simple multi-threading

Step 1: create a console application to simulate a multi-threaded environment

/// <summary>

/// The class simulates a multi-threaded environment

/// </summary>

class Program

{

    static void Main(string[] args)

    {

        const string DEFAULT_ARGUMENT = "Naz-Tek";

        // Create an instance of a parameter class

        MyParamter parameter = new MyParamter(DEFAULT_ARGUMENT);

        // Create an instance of a class to provide a method to run on a separate thread

        MyProcessor processor = new MyProcessor(parameter);

        // Create an instance of the delegate to encapsulate the method to execute on a separate thread

        System.Threading.ThreadStart start = new System.Threading.ThreadStart(processor.Process);

        // Create another thread to execute in parallel to the main thread

        System.Threading.Thread myBackgroundThread = new System.Threading.Thread(start);

        // Kickstart the new thread

        myBackgroundThread.Start();

        // Terminate the newly created thread

        const int MAX_THREAD_TERMINATION_WAIT_PERIOD = 1000;

        myBackgroundThread.Join(MAX_THREAD_TERMINATION_WAIT_PERIOD);

        // Inspect the parameter modified by the second thread

        System.Console.WriteLine(parameter.Name);

        System.Console.ReadLine();

    }

}

Step 2: create a class to provide a method to execute on a thread other than the main thread

/// <summary>

/// The class provides a method for multi-threaded execution

/// </summary>

internal sealed class MyProcessor

{

    const string DEFAULT_MODIFIED_ARGUMENT = "Naz-Tek supercharged";

    private MyParamter _parameter;

    internal MyProcessor(MyParamter parameter) { _parameter = parameter; }

    /// <summary>

    /// The method to run on a separate thread

    /// </summary>

    /// <remarks>

    /// This method must return void and accept no arguments

    /// </remarks>

    internal void Process()

    {

        // Modify the parameter as appropriate

        _parameter.Name = DEFAULT_MODIFIED_ARGUMENT;

    }

}

Step 3: create a class to encapsulate data to be modified in the multithreaded environment

/// <summary>

/// The class encapsulates data to be modified in a multi-threaded environment

/// </summary>

internal sealed class MyParamter

{

    string _name;

    internal string Name

    {

        get { return _name; }

        set { _name = value; }

    }

    internal MyParamter(string name) { _name = name; }

}

Multi-threading & exception handling

Step 1: create a console application to simulate a multi-threaded environment.  One method to create a secondary thread and another method to listen to exceptions on that thread

/// <summary>

/// The class simulates a multi-threaded environment

/// </summary>

class Program

{

    static void Main(string[] args)

    {

        const string DEFAULT_ARGUMENT = "Naz-Tek";

        // Create an instance of a parameter class

        MyParamter parameter = new MyParamter(DEFAULT_ARGUMENT);

        // Create an instance of a class to provide a method to run on a separate thread

        MyProcessor processor = new MyProcessor(parameter);

        // Create an instance of the delegate to encapsulate the method to execute on a separate thread

        System.Threading.ThreadStart start = new System.Threading.ThreadStart(processor.Process);

        // Create another thread to execute in parallel to the main thread

        System.Threading.Thread myBackgroundThread = new System.Threading.Thread(start);

        // Attach a listener to the secondary thread processor's exception publisher

        processor.SecondaryThreadException += new ExceptionHandler(processor_SecondaryThreadException);

        // Kickstart the new thread

        myBackgroundThread.Start();

        // Terminate the newly created thread

        const int MAX_THREAD_TERMINATION_WAIT_PERIOD = 1000;

        myBackgroundThread.Join(MAX_THREAD_TERMINATION_WAIT_PERIOD);

        // Inspect the parameter modified by the second thread

        System.Console.WriteLine(string.Format("Main thread id: {0}, data: {1}", System.Threading.Thread.CurrentThread.ManagedThreadId.ToString(), parameter.Name));

        System.Console.ReadLine();

    }

    /// <summary>

    /// The method is wired to execute when a secondary thread raises exceptions

    /// </summary>

    /// <param name="sender">The object instance raising the exception</param>

    /// <param name="e">The EventArgs subclass object encapsulating the exception details</param>

    /// <remarks>

    /// The method is static, which should be avoided if a class instance is available

    /// </remarks>

    static void processor_SecondaryThreadException(object sender, ExceptionEventArgs e)

    {

        System.Console.WriteLine(string.Format("Problem in thread (id: {0}), message: {1}", e.ThreadId.ToString(), e.Exception.Message));

    }

}

Step 2: create a class to provide a method to execute on the secondary thread as well as publish exceptions through a custom event

/// <summary>

/// The class provides a method for multi-threaded execution

/// </summary>

internal sealed class MyProcessor

{

    /// <summary>

    /// The event is raised when an exception occurs in the method executing on the secondary thread

    /// </summary>

    internal event ExceptionHandler SecondaryThreadException;

 

 

    private const string DEFAULT_MODIFIED_ARGUMENT = "Naz-Tek supercharged";

    private MyParamter _parameter;

    internal MyProcessor(MyParamter parameter) { _parameter = parameter; }

    /// <summary>

    /// The method to run on a secondary thread

    /// </summary>

    /// <remarks>

    /// This method must return void and accept no arguments

    /// </remarks>

    internal void Process()

    {

        try

        {

            // Simulate naturally occuring exception

            throw new System.Exception("There was problem");

            // Modify the parameter as appropriate

            _parameter.Name = DEFAULT_MODIFIED_ARGUMENT;

        }

        catch (System.Exception ex)

        {

            // Publish the exception

            OnSecondaryThreadException(this, new ExceptionEventArgs(System.Threading.Thread.CurrentThread.ManagedThreadId, ex));

        }

    }

    /// <summary>

    /// Encapsulates exception publishing, best practice

    /// </summary>

    /// <param name="sender">The object instance that raised the exception</param>

    /// <param name="e">The EventArgs subclass object instance that encapsulates the exception details</param>

    internal void OnSecondaryThreadException(object sender, ExceptionEventArgs e)

    {

        // Raise the exception if there's at least one listener

        if (SecondaryThreadException != null)

            SecondaryThreadException(sender, e);

    }

}

Step 3: create a delegate to facilitate exception publishing and subscription

/// <summary>

/// The handler that facilitates the exception transportation between threads

/// </summary>

/// <param name="sender">Represents publisher object instance</param>

/// <param name="e">Provides published data encapsulation</param>

internal delegate void ExceptionHandler(object sender, ExceptionEventArgs e);

Step 4: create an EventArgs subclass to encapsulate exception details

/// <summary>

/// Provides a means to encapsulate data to publish

/// </summary>

internal sealed class ExceptionEventArgs : System.EventArgs

{

    private System.Exception _exception;

    private int _threadId;

    internal System.Exception Exception { get { return _exception; } }

    internal int ThreadId { get { return _threadId; } }

    internal ExceptionEventArgs(int threadId, System.Exception exception)

    {

        _threadId = threadId;

        _exception = exception;

    }

}

Step 5: create a class to encapsulate data to be modified in the multithreaded environment

/// <summary>

/// The class encapsulates data to be modified in a multi-threaded environment

/// </summary>

internal sealed class MyParamter

{

    string _name;

    internal string Name

    {

        get { return _name; }

        set { _name = value; }

    }

    internal MyParamter(string name) { _name = name; }

}

Smart client thread sync
Using thread pool