Jeffrey Richter's Blog

Integrating your Application’s Threading Model with the Asynchronous Programming Model

In version 2.0 of the .NET Framework, Microsoft introduced the System.Threading. SynchronizationContext class. Simply stated, a SynchronizationContext-derived object connects an application model to its threading model. The FCL defines several classes derived from SynchronizationContext, but usually you will not deal directly with these classes; in fact, many of them are not publicly exposed or documented. Here is what the SynchronizationContext class looks like (I show only the members relevant to this discussion):

public class SynchronizationContext {
// Gets the SynchronizationContext-derived object
// associated with the calling thread
public static SynchronizationContext Current { get; }

// Invokes d asynchronously
public virtual void Post(SendOrPostCallback d, object state);

// Invokes d synchronously
public virtual void Send(SendOrPostCallback d, object state);
}

// SendOrPostCallback is a delegate defined like this:
public delegate void SendOrPostCallback(Object state);

Console and NT service applications have no threading model and therefore calling SynchronizationContext.Current will return null. For GUI applications such as Windows Forms, Windows Presentation Foundation, and Silverlight, the threading model dictates that all UI components must be updated by the thread that created them. So, when a GUI thread calls SynchronizationContext.Current, a reference to an object that knows how to invoke the d delegate on the calling GUI thread is returned. For ASP.NET applications, calling SynchronizationContext.Current returns a reference to an object that knows how to associates the original client request's identity and culture with the calling thread before invoke the d delegate (which will be invoked on the same thread that calls SynchronizationContext's Post or Send methods. In fact, for an ASP.NET SynchronizationContext object, the Post and Send methods do the exact same thing: they call the d delegate synchronously.

When working with the .NET Framework's Asynchronous Programming Model (APM), understanding the SynchronizationContext is extremely important as it allows the callback method to be invoked using your application's thread model. To simplify this, I wrote the following little method:

private static AsyncCallback SyncContextCallback(AsyncCallback callback) {
// Capture the calling thread's SynchronizationContext-derived object
SynchronizationContext sc = SynchronizationContext.Current;

// If there is no SC, just return what was passed in
if (sc == null) return callback;

// Return a delegate that, when invoked, posts to the captured SC a method that
// calls the original AsyncCallback passing it the IAsyncResult argument
return asyncResult => sc.Post(
result => callback((IAsyncResult)result), asyncResult);
}

This method turns a normal AsyncCallback method into an AsyncCallback method that is invoked via the SynchronizationContext-derived object associated with the calling thread.

On Sep 22 2010 5:44 AMBy jeffreyr With 5 Comments

Comments (5)

  1. WOW! Thanks Jeff, this is awsome. I have been looking for a clean way to do this for a while. This is the best I have seen.

  2. Nikos Baxevanis

    This very cool method is also useful when you want to call existing code asynchronously, by doing this for ex.:

    Action a = SomeMethod;

    a.BeginInvoke(SyncContextCallback((ar) => {
    a.EndInvoke(ar);
    // Do something here (which executes on the UI thread).
    }), null);


    public void SomeMethod() { /* Long running op. here. */};

  3. Hi Jeffrey,

    About a year ago I did a short research on APM. One of the result was that when async operation completes a callback is executed on one of IO threads from the .Net thread pool (you wrote in your book about these threads that they are only used to call a callback when async IO operation completes).

    I decided that as these IO threads are essentially used only to wait on IO completion port for async IO operation to complete it is safe to call from the callback another IO operation _synchronously_.

    My idea was as synchronous operation is essentially made asynchronously but it just waits for IO operation (made asynchronously by OS) on IO completion port and blocks current thread while waiting. So if we call it synchronously from IO thread we do the same as it were called asynchronously with only difference that in this case just another IO thread will be blocked waiting on IO completion port.

    So am I correct or it is a bad practice and I missed something when thought about that?

    PS. I've just read this article and remembered this idea. As i didn't found better place to ask this question I posted it here. BTW your books are brilliant! I enjoy reading them.

    Thanks,

    Mikhail Mikheev

  4. Hi Jeffrey,
    Your post above suggests that "For ASP.NET applications, calling SynchronizationContext.Current" works as one might expect. I recently submitted a simple ASP.NET web form example to the ASP.NET forum in which the SynchronizationContext.Current is consistently null in a worker thread, see the link
    http://forums.asp.net/t/1949551.aspx?SynchronizationContext+is+null+in+a+worker+thread+on+a+simple+ASP+NET+Form+when+I+try+to+update+a+label
    I would greatly appreciate it, if you could comment on the example, it was developed on VS2013.
    Thanks Michael

Leave a Comment