SynchronizationContext Class

The SynchronizationContext class (System.Threading) provides a mechanism to invoke delegates on the same thread that the SynchronizationContext represents.

/// <summary>
/// Dispatches an asynchronous message to a synchronization context.
/// </summary>
/// <param name="d">The SendOrPostCallback delegate to call</param>
/// <param name="state">The object passed to the delegate</param>
public virtual void Post(SendOrPostCallback d, Object state)

/// <summary>
/// Dispatches a synchronous message to a synchronization context.
/// </summary>
/// <param name="d">The SendOrPostCallback delegate to call</param>
/// <param name="state">The object passed to the delegate</param>
public virtual void Send(SendOrPostCallback d, Object state)

The post and send methods take a SendOrPostCallback delegate that represents the method to be invoked on the same thread that the SynchronizationContext represents, and an object representing information to pass to that delegate.

The SynchronizationContext class provides a static property getter that gets the synchronization context for the current thread.

public static SynchronizationContext Current { get; }

This property is useful for propagating a synchronization context from one thread to another.

How do we use it?

The goal is to ensure that the caller thread into any background worker class creates the Synchronization context, which will then be used to signal the caller on the same thread as the caller when the operation is completed.

public class BackgroundWorker
{
    public event Action<object> WorkCompleted;

    public BackgroundWorker()
    {
        this.context = SynchronizationContext.Current;
        if (this.context == null)
        {
            context = new SynchronizationContext();
        }

        this.workerThread = new Thread(this.DoWork);
        this.workerThread.Start();
    }

    private void DoWork()
    {
        // ...
        // Do some work
        // ...

        // Signal the caller that we are done.
        object results = new object();
        context.Post(delegate(object state)
        {
            if (this.WorkCompleted != null)
            {
                this.WorkCompleted(results);
            }
        }, results);
    }

    private SynchronizationContext context;
    private Thread workerThread;
}

WarningThe above code is dangerous! The creation of a SynchronizationContext instance for a thread can lead to nasal demons. There are possible conditions which may lead to Form’s threads Synchronization context (known as WindowsFormsSynchronizationContext) not being used correctly.

AsyncOperationManager Class to the Rescue

The AsyncOperation and AsyncOperationManager class (System.ComponentModel) removes the requirement for accessing or creating SynchronizationContexts. They provide a thread-safe, context-safe environment to access a handle to the current threads SynchronizationContext, and then a safe means to use this for sending/posting information back to that thread’s context.

The AsyncOperation class wraps the SynchronizationContext, and is used for sending/posting messages.

Use the AsyncOperationManager to retrieve the AsyncOperation class which wraps the SynchronizationContext we’ll use for posting. This safely creates a SynchronizationContext object belonging to the thread in which this operation was called.

Below is the previous example re-written using these new classes.

public class BackgroundWorker
{
    public event Action<object> WorkCompleted;

    public BackgroundWorker()
    {
        this.asyncOperation = AsyncOperationManager.CreateOperation(null);

        this.workerThread = new Thread(this.DoWork);
        this.workerThread.Start();
    }

    private void DoWork()
    {
        object results = new object();
        this.asyncOperation.Post(delegate(object state)
        {
            if (this.WorkCompleted != null)
            {
                this.WorkCompleted(results);
            }
        }, results);
    }

    private AsyncOperation asyncOperation;
    private Thread workerThread;
}

Making Thread-Safe Calls on Windows Controls/Forms

InvokeRequired / BeginInvoke Method

To ensure a method is thread safe for windows controls/forms, it is common to implement the InvokeRequired/BeginInvoke pattern.

// No Parameter Example
void doSomething()
{
    if (this.InvokeRequired)
    {
        this.BeginInvoke(new Action(doSomething));
        return;
    }

    // Insert code that does work here
}

// Function with Parameter example.
void doSomething(int param1, string param2)
{
    if (this.InvokeRequired)
    {
        this.BeginInvoke(
            new Action<int, string>(doSomething), 
            new object[] { param1, param2});
        return;
    }

    // Insert code that does work here
}

Functionally, this works fine. The question is can we make it better? I believe the answer is yes.

Currently there are two main problems with this approach:

  • For a parametrized function, when updated, the corresponding delegate signature must also be updated.
  • Too often, I’ve seen the return statement missing within the if block leading to errors that are not found until run-time

The aim is to define a software architecture that will simplify the code, and improve code correctness.

Proposed Solution

A GUIExtensions static class has been created containing two static functions that allow us to execute the code on the thread that the control/form was created either synchronously or asynchronously.

using System.ComponentModel;
public static class GUIExtensions
{
  /// <summary> 
  /// Executes the delegate immediately if the current thread is the thread
  /// that created this object. Otherwise, asynchronously executes the delegate
  /// on the thread that created this object.
  /// </summary>
  /// <param="control">The control of interest</param>
  /// <param="code">The code to execute on the control's creation thread</param>
  /// <remarks>
  /// If you need to execute the code immediately, use the <code>UIThreadInvoke</code>
  /// method instead.
  /// </remarks>
  static public void UIThread(this ISynchronizeInvoke control, Action code)
  {
    // Determine whether the current thread is the creation thread of the control.
    if (control.InvokeRequired)
    {
      // Asynchronously execute the delegate on the thread that created this object.
      control.BeginInvoke(code, null);
      return;
    }

    // Just invoke the code.
    code.Invoke();
  }

  /// <summary>
  /// Executes the delegate immediately if the current thread is the thread
  /// that created this object. Otherwise, synchronously executes the delegate
  /// on the thread that created this object and marshals the call to the creating thread.
  /// </summary>
  /// <param name="control">The control of interest.</param>
  /// <param name="code">The code to execute on the control's creation thread.</param>
  static public void UIThreadInvoke(this ISynchronizeInvoke control, Action code)
  {
    // Determine whether the current thread is the creation thread of the control.
    if (control.InvokeRequired)
    {
      // Synchronously execute the delegate on the thread that created
      // this object and marshals the call to the creating thread.
      control.Invoke(code, null);
      return;
    }

    // Just invoke the code.
    code.Invoke();
  }
}

Example Usage

The best way to see the power of this proposed solution is to have a look at it in action.

The UIThread static functions may be called with anonymous functions (as shown below). Note that there are a couple of significant advantages of using this approach:

  • If the doSomething() signature changes, you do NOT have to update a inner-code delegate signature
  • You can use the function parameters directly
void doSomething(int param1, string param2)
{
    this.UIThread(delegate
    {
        // Insert code that does work here
        // NOTE: you can use param1, param2 directly here. 
    });
}

The UIThread static functions may also be called with lambda functions. This allows you to do quick in-line updates of GUI components within background threads.

void doSomething(int param1, string param2)
{
    // Insert code here that's doing something

    // Now update a GUI Text box on the correct thread
    this.UIThread(() => this.myTextBox.Text = "Some Text";);

    // Insert code here that's doing something  
}

Mutable & Immutable Classes

This post describes a method for creating a mutable and immutable version of the same class. At a first glance, there may seem to be two obvious ways to approach this problem; either:

  1. Create a base Mutable Class and derive a Immutable version of this class; or
  2. Create a base Immutable Class and derive a Mutable version of this class.

To help decide which may be the best design, we can refer back to the principles of object-oriented design. The Liskov Substitution Principle states that subtypes must be substitutable for their base types.

Don’t inherit unless you really are (and can be treated in all respects) like what you derive from.

Keeping this in mind, we can see that solution one would violate this principle. You can not treat an Immutable object as a Mutable object. i.e. you would not want a user to be able to cast an immutable object, to it’s parents-type, so that the user could then mutate that object.

A simple implementation of solution two is shown below.

    public class ImmutableClass
    {
        public int SomeProperty { get; protected set; }
        public string AnotherProperty { get; protected set; }
    }

    public class MutableClass : ImmutableClass
    {
        public new int SomeProperty
        {
            get
            {
                return base.SomeProperty;
            }
            set
            {
                base.SomeProperty = value;
            }
        }

        public new string AnotherProperty
        {
            get
            {
                return base.AnotherProperty;
            }
            set
            {
                base.AnotherProperty = value;
            }
        }
    }