SynchronizationContext, when does it flow and when does it not?

1.2k views Asked by At

I'm trying to learn about SynchronizationContext and friends. If I set a custom synchronization context at the start of e.g. a console app. Under what conditions will the current synchronization context flow with my async operations? Are there differences between Task and others, e.g. Delegate.BeginInvoke ?

void Main()
{
    SynchronizationContext.SetSynchronizationContext(new FooContext());
    Action a = () =>
    {
         var current = SynchronizationContext.Current;
         //current is null here
    };
    a.BeginInvoke(null,null);

    ...sleep

If I execute stuff on the thread pool, am I forced to assign a synchronization context to that specific thread that is currently executing my work?

1

There are 1 answers

0
Stephen Cleary On BEST ANSWER

Under what conditions will the current synchronization context flow with my async operations?

When an async method performs an await, by default it will capture a current context and use that to resume the async method. This context is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. I describe this behavior in my async intro blog post, my MSDN article on SynchronizationContext, and my MSDN article on async best practices.

Are there differences between Task and others, e.g. Delegate.BeginInvoke?

This behavior is unique to async and await. Delegate.BeginInvoke means "run this delegate on a thread pool thread", so it doesn't propagate the SynchronizationContext. Neither do more modern approaches such as Task.Run.

If I execute stuff on the thread pool, am I forced to assign a synchronization context to that specific thread that is currently executing my work?

In general, you shouldn't install a synchronization context on a thread you don't own. If you do place one on a thread pool thread, it should be removed before the thread is returned to the thread pool. More likely, if you're installing a synchronization context, you just shouldn't ever give the thread back (a custom synchronization context is commonly associated with a "main loop" for that thread).

in the example above, logical call context flows but not synchronization context. any pointers to why this is the case would be interesting.

The other contexts are even less documented. Stephen Toub has the definitive post on the subject. In essence, some data such as security must flow; most other data does not.