Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can ConfigureAwait(false) in a library lose the synchronization context for the calling application?

I've read the advice many times from people smarter than me, and it has few caveats: Always use ConfigureAwait(false) inside library code. So I'm fairly certain I know the the answer, but I want to be 100%. The scenario is I have a library that thinly wraps some other asynchronous library.

Library code:

public async Task DoThingAsyc() {
    // do some setup
    return await otherLib.DoThingAsync().ConfigureAwait(false);
}

Application code:

// need to preserve my synchronization context
await myLib.DoThingAync();
// do I have my context here or did my lib lose it?
like image 404
Todd Menier Avatar asked Sep 12 '15 19:09

Todd Menier


People also ask

What does ConfigureAwait false do?

If we set 'ConfigureAwait(true)' then the continuation task runs on the same thread used before the 'await' statement. If we set 'ConfigureAwait(false)' then the continuation task runs on the available thread pool thread.

When would you not use ConfigureAwait false?

If the await task. ConfigureAwait(false) involves a task that's already completed by the time it's awaited (which is actually incredibly common), then the ConfigureAwait(false) will be meaningless, as the thread continues to execute code in the method after this and still in the same context that was there previously.

What does ConfigureAwait () do?

ConfigureAwait(continueOnCapturedContext: false) is used to avoid forcing the callback to be invoked on the original context or scheduler. This has a few benefits: Improving performance.

Is ConfigureAwait true default?

To improve performance and avoid potential deadlocks, use ConfigureAwait(false) in any non-UI code. The exception here is app-level code, such as Windows Forms, WPF, and ASP.NET. ConfigureAwait(true) corresponds to the default behavior and does nothing meaningful, therefore such calls can be safely omitted.


2 Answers

No.

The capturing of the SynchronizationContext happens on await. ConfigureAwait configures the specific await.

If the application calls a library's async method and awaits it the SC is captured on the spot regardless of what happens inside the call.

Now, because the async method's synchronous part (which is the part before the first await) is executed before a task is returned to be awaited, you can mess around with the SynchronizationContext there, but ConfigureAwait doesn't do that.


In your specific example you seem to be returning the result of ConfigureAwait from the async method. That can't happen because ConfigureAwait returns the ConfiguredTaskAwaitable struct. If however we change the method return type:

public ConfiguredTaskAwaitable DoThingAsyc() 
{
    return otherLib.DoThingAsync().ConfigureAwait(false);
}

Then awaiting it will indeed affect the calling code's await behavior.

like image 190
i3arnon Avatar answered Oct 07 '22 01:10

i3arnon


Example from http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx

... logically you can think of the following code:

await FooAsync();
RestOfMethod();

as being similar in nature to this:

var t = FooAsync();
var currentContext = SynchronizationContext.Current;
t.ContinueWith(delegate
{
    if (currentContext == null)
        RestOfMethod();
    else
        currentContext.Post(delegate { RestOfMethod(); }, null);
}, TaskScheduler.Current);

which means you should have your context back after the await myLib.DoThingAync(); call.

like image 43
m0sa Avatar answered Oct 07 '22 00:10

m0sa