Why does ConfigureAwait causes a deadlock in the following scenario? - c#

I have a WinForms application with a single button and a single button Click event handler. In the event handler, I have this code:
NOTE: DoWorkAsync() returns a Task<int>.
var result = obj.DoWorkAsync().ConfigureAwait(false).GetAwaiter().GetResult();
Implementation of DoWorkAsync():
public async Task<int> DoWorkAsync()
{
await Task.Delay(3000);
return 200;
}
This code will deadlock but I am not sure why. I have configured the task not to continue on the UI thread after GetResult() returns. So why does the code deadlock instead of running the next line of code?

I have configured the task
ConfigureAwait is for configuring awaits, not tasks. There's nothing that awaits the result of the ConfigureAwait, so that's an indication that it's being misused here.
I have configured the task not to continue on the UI thread after GetResult() returns.
Not really. As explained above, the ConfigureAwait has no effect here. More broadly, the code is (synchronously) blocking on the task, so the UI thread is blocked and then will resume executing after GetResult() returns.
This code will deadlock but I am not sure why.
Walk through it step by step. Read my blog post on async/await if you haven't already done so.
Note that this:
var result = obj.DoWorkAsync().ConfigureAwait(false).GetAwaiter().GetResult();
is pretty much the same as this:
var doWorkTask = obj.DoWorkAsync();
var result = doWorkTask.ConfigureAwait(false).GetAwaiter().GetResult();
Asynchronous methods begin executing synchronously, just like any other method. In this case, DoWorkAsync is called on the UI thread.
DoWorkAsync calls Task.Delay (also synchronously).
Task.Delay returns a task that is not complete; it will complete in 3 seconds. Still synchronous, and on the UI thread.
The await in DoWorkAsync checks to see if the task is complete. Since it is not complete, await captures the current context (the UI context), pauses the method, and returns an incomplete task.
The calling code calls ConfigureAwait(false) on the returned task. This essentially has no effect.
The calling code calls GetAwaiter().GetResult() on the (configured) returned task. This blocks the UI thread waiting on the task.
3 seconds later, the task returned by Task.Delay completes, and the continuation of DoWorkAsync is scheduled to the context captured by its await - the UI context.
Deadlock. The continuation is waiting for the UI thread to be free, and the UI thread is waiting for the task to complete.
In summary, a top-level ConfigureAwait(false) is insufficient. There are several approaches to sync-over-async code, with the ideal being "don't do it at all; use await instead". If you want to directly block, you need to apply ConfigureAwait(false) on every await on the method that is called (DoWorkAsync in this case), as well as the transitive closure of all methods called starting from there.
Clearly, this is a maintenance burden, and occasionally impossible (i.e., third-party libraries missing a ConfigureAwait(false)), and that's why I don't usually recommend this approach.

Related

How does control flow when there is synchronous code in awaited function?

Say in button click event I have:
await someFn()
And in the someFn code, I have got some synchronous code and some asynchronous code.
As per online reading on this topic, they all seem to say that when await is encountered, control immediately goes back the caller (UI thread in this case) while the asynchronous waiting happens.
I haven't come across situation where it is explained what happens when there is some synchronous code just before the async code in the awaited function. Does the synchronous code execute before passing the control to the caller (UI thread)?
I know that- had it been run using await Task.Run(...) instead of await someFn() then it would execute in a separate thread.
It is true that "when await is encountered, control immediately goes back the caller", under the condition that the awaitable will not be completed at the await point. Otherwise (if the awaitable is already completed) the control will stay inside the method, by executing immediately the code that follows the await.
That's all that influences the behavior of the await operator: the result of the IsCompleted property of the awaiter. It doesn't matter if the method that produced the awaitable included synchronous code or not. The await doesn't know, and doesn't care. A synchronous code block inside the someFn will indeed make a difference regarding the responsiveness of your application, but that has nothing to do with the await. To understand why, it may help to rewrite your code in a more verbose but equivalent form. This:
await someFn();
...is equivalent to this:
Task t = someFn();
await t;
The UI of your application will freeze because the someFn() blocks, not because the await t blocks. Unless of course you have created some wicked task-like awaitable type, that blocks when the IsCompleted property of its awaiter is invoked.
If you see an await in your code, for example when you see var obj = await someFn();, then you can treat is as a placeholder for the following code:
var waitingTask task = someFn();
if (!task.IsCompleted) {
var thisTask = [Magic]
return thisTask.Task;
}
var obj = waitingTask.Result;
In reality the code is rewritten to something more complex, a so called state machine. The [Magic] part is hard to explain but what it does is capturing the current SynchronizationContext, the current line that is executing and the task it's waiting on.
As soon as the task that you are waiting on completes, it will try to restore this method on the captured SynchronizationContext and continue working. It's this SynchronizationContext that tells you if you are working on the UI thread or not. This is why it's advised to use ConfigureAwait(false) to avoid restoring on the UI thread if it's not needed, avoiding possible slow downs on the UI for executing code that does nothing with the UI.
The main point here is that you see that the code before an await is executed synchronously/immediately. Even the code inside the function that you are calling is executed synchronously/immediately until you reach an await in that function that is not completed. From this point on the stack 'rewinds', creating (returning) a new Task on each point that waits for the underlying code to complete. If the lowest task completes, only that task that waits for it is 'revived', all tasks above it still stay 'waiting' and only when that bottom function has reached it real end of the method will it 'revive' the task that is waiting for it's result, and so on to the top of the stack.

Can synchronous methods continue their execution before an asynchronous sub-call has completed?

I have issues understanding a detail about async programming in C#.
Lets say I have a common async method, that has a few await statements in it. Lets say I have another method, which is not async, but calls the first method.
public void DoSomething(){
DoSomethingAsync()
...
}
public async Task DoSomethingAsync(){
...
await ...
...
}
I know i could just use Wait() or some other synchronization technique, but i dont just want to throw stuff at problems without knowing what happens.
Will DoSomething continue execution before DoSomethingAsync is completed? I know that this would happen if DoSomething were to be declared async, but it isn't.
Or to be more general: Can synchronous methods continue their execution before an asynchronous sub-call has completed?
TL;DR It continues
Can synchronous methods continue their execution before an
asynchronous sub-call has completed?
Of course it can, if a synchronous method has to wait an asynchronous method to finish, what's the purpose of going asynchronous? (It can wait as well, depending on what you want to achieve)
async/await pattern in your code will create a state machine that can be recovered later. By the time your code hits await, the task you await on will be pushed to the task scheduler and might be executed in some threadpool thread. The async method returns and let the synchronous method continue.
When the task is finished, the state machine recovers the context, and everything in DoSomethingAsync after await continues. On which thread it would run? This depends on if you set ConfigureAwait and the threading model of your program. For example, for a WPF application, by default, it comes back to the main thread, and that's why wait + await can lead to deadlocks.
What happens is:
DoSomething calls DoSomethingAsync.
Then a synchronous! order starts until the first "await" is reached.
With this await, the DoSomethingAsync returns a Task object the has status "not finished yet". But as you do not assign this return value and also do nothing else special your DoSomething continues.
In the absence of the await operator this method will behave as if this call is not awaited, execution of the current method continues before the call is completed
The compiler will warn you:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs4014?f1url=%3FappId%3Droslyn%26k%3Dk(CS4014)
Can synchronous methods continue their execution before an asynchronous sub-call has completed?
As others have noted, the answer to this is "yes".
All asynchronous methods begin executing synchronously. They return a task that represents the completion of that asynchronous method. The task is completed when the asynchronous method is completed. If the asynchronous method returns a result, then the task is completed with a result value. If the asynchronous method throws an exception, then the task is completed with an exception (i.e., faulted).
However, this also means that there is are some problems with the code you've posted. Specifically, it's doing a kind of "fire and forget", and that's dangerous.
This code is just ignoring the task returned from DoSomethingAsync:
public void DoSomethingElse(){
DoSomethingAsync()
...
}
So that means it's saying "start doing something" and it's also saying "I don't care if or when that 'something' completes, and I don't care if it throws an exception". There are a couple problems with this: 1) since your app doesn't know when "something" completes, it can't know when it's safe to shut down, and 2) your app won't be notified if "something" fails.
In the vast, vast majority of scenarios, that means the app has bugs. "Fire and forget" is only appropriate when doing an operation where it doesn't actually matter if the operation fails or isn't even completed. There are very few operations where this is the case.
This is why - as a general rule - tasks should eventually be awaited. If you want to start an operation and then do other things and then await that operation to complete, that's not uncommon:
public async Task DoSomethingElseAsync() {
var task = DoSomethingAsync();
... // other synchronous/asynchronous work.
await task; // asynchronously wait for DoSomethingAsync to complete,
// and propagate any exceptions.
}

Use ConfigureAwait(false) or Task.Run to avoid blocking UI Thread

I'm trying to find out which approach is better let's say we have a button, after user clicks it we perform 1. Send a async request using httpClient
2. Some heavy synchronous staff like computations and saving data to a database.
Like that:
button1.Click += async(sender, e) =>
{
bool a = await Task.Run(async () => { return await MyTask1();});
}
async Task<bool> MyTask1()
{
await new HttpClient().GetAsync("https://www.webpage.com");
DoHeavyStuffFor5minutes();
return true;
}
button2.Click += async(sender, e) =>
{
bool a = await MyTask2();
}
async Task<bool> MyTask2()
{
await new HttpClient().GetAsync("https://www.webpage.com").ConfigureAwait(false);
DoHeavyStuffFor5minutes();
}
From what i understand GetAsync does not block my UI thread because underneath it uses a method which make it runs on different thread perhaps Task.Run or any other method that allows that.
But DoHeavyStuffFor5Minutes will block my UI because it will get called on the caller SynchornizationContext.
So i read that using ConfigureAwait(false) will make code after GetAsync do not run on the same SynchornizationContext as the caller. My question is, which approach is better first or the second one?
There is no need to execute HttpClient.GetAsync on a background thread using Task.Run since the HTTP request is truly asynchronous by nature so in this case your second approach is better that the first one.
When the Task returned by GetAsync has eventually finished, the remainder or MyTask2() will be executed on a thread pool thread assuming you opt out of capturing the context by calling ConfigureAwait(false).
Note however that ConfigureAwait(false) does not guarantee that the callback or remainer won't be run in the original context in all cases.
From Stephen Toub's blog post:
Does ConfigureAwait(false) guarantee the callback won’t be run in the original context?
"No. It guarantees it won’t be queued back to the original contex...but that doesn’t mean the code after an await task.ConfigureAwait(false) won’t still run in the original context. That’s because awaits on already-completed awaitables just keep running past the await synchronously rather than forcing anything to be queued back. So, if you await a task that’s already completed by the time it’s awaited, regardless of whether you used ConfigureAwait(false), the code immediately after this will continue to execute on the current thread in whatever context is still current."
So you might want to off-load DoHeavysTuffFor5minutes, which I assume is a CPU-bound and potentially long-running operation, to a background thread using Task.Run to be on the safe side. At least in the general case.
Also note that a method that is named *Async and returns a Task or Task<T> might still block the calling thread depending on its implementation. In general, this may be a reason to use your first approach of a calling both methods on a background thread in order to avoid blocking the UI thread. If you however use well-implemented APIs, such as HttpClient, this isn't an issue though.

What code is actually executed "multi-threadedly" in async/await pattern?

In this code:
public async Task v_task()
{
await Task.Run(() => Console.WriteLine("Hello!"));
}
public async void v1()
{
await v_task();
// some other actions...
}
public void ButtonClick()
{
v1();
Console.WriteLine("Hi!");
}
Which methods above are actually executed in parallel in the async/await generated lower thread pool if ButtonClick is called?
I mean, what should be my concerns about race conditions working with async/await? All async methods are mandatory executed in the same caller's thread? Should I use mutex on possible shared state? If yes, how could I detect what are the shared state objects?
Which methods above are actually executed in parallel in the async/await generated lower thread pool if ButtonClick is called?
Only the Console.WriteLine within the Task.Run.
I mean, what should be my concerns about race conditions working with async/await?
I suggest you start by reading my async intro, which explains how await actually works.
In summary, async methods are usually written in a serially asynchronous fashion. Take this code for example:
CodeBeforeAwait();
await SomeOtherMethodAsync();
CodeAfterAwait();
You can always say that CodeBeforeAwait will execute to completion first, then SomeOtherMethodAsync will be called. Then our method will (asynchronously) wait for SomeOtherMethodAsync to complete, and only after that will CodeAfterAwait be called.
So it's serially asynchronous. It executes in a serial fashion, just like you'd expect it to, but also with an asynchronous point in that flow (the await).
Now, you can't say that CodeBeforeAwait and CodeAfterAwait will execute within the same thread, at least not without more context. await by default will resume in the current SynchronizationContext (or the current TaskScheduler if there is no SyncCtx). So, if the sample method above was executed in the UI thread, then you would know that CodeBeforeAwait and CodeAfterAwait will both execute on the UI thread. However, if it was executed without a context (i.e., from a background thread or Console main thread), then CodeAfterAwait may run on a different thread.
Note that even if parts of a method run on a different thread, the runtime takes care of putting any barriers in place before continuing the method, so there's no need to barrier around variable access.
Also note that your original example uses Task.Run, which explicitly places work on the thread pool. That's quite different than async/await, and you will definitely have to treat that as multithreaded.
Should I use mutex on possible shared state?
Yes. For example, if your code uses Task.Run, then you'll need to treat that as a separate thread. (Note that with await, it's a lot easier to not share state at all with other threads - if you can keep your background tasks pure, they're much easier to work with).
If yes, how could I detect what are the shared state objects?
Same answer as with any other kind of multi-threaded code: code inspection.
If you call an async function, your thread will perform this function until it reaches an await.
If you weren't using async-await, the thread would yield processing until the awaited code was finished and continue with the statement after the await.
But as you are using async-await, you told the compiler that whenever the thread has to wait for something, you have some other things it can do instead of waiting, The thread will do those other things until you say: now await until your original thing is finished.
Because of the call to an async function we are certain that somewhere inside there should be an await. Note that if you call an async function that doesn't await you get a compiler warning that the function will run synchronously.
Example:
private async void OnButton1_clickec(object sender, ...)
{
string dataToSave = ...;
var saveTask = this.MyOpenFile.SaveAsync(dataToSave);
// the thread will go into the SaveAsync function and will
// do all things until it sees an await.
// because of the async SaveAsync we know there is somewhere an await
// As you didn't say await this.MyOpenfile.SaveAsync
// the thread will not wait but continue with the following
// statements:
DoSomethingElse()
await saveTask;
// here we see the await. The thread was doing something else,
// finished it, and now we say: await. That means it waits until its
// internal await is finished and continues with the statements after
// this internal await.
Note that even if the await somewhere inside SaveAsync was finished, the thread will not perform the next statement until you await SaveTask. This has the effect that DoSomethingElse will not be interrupted if the await inside the SaveAsync was finished.
Therefore normally it's not useful to create an async function that does not return either a Task or a Task < TResult >
The only exception to this is an event handler. The GUI doesn't have to wait until your event handler is finished.

.NET async\await fundamentals

After playing with .NET 4.5 async\await framework I have a question.
Let's look at this program (the msdn example):
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
DoIndependentWork();
string urlContents = await getStringTask;
return urlContents.Length;
}
void DoIndependentWork()
{
resultsTextBox.Text += "Working . . . . . . .\r\n";
}
The program will run in this order:
new HttpClient.
GetStringAsync invoke synchronously.
In some point, GetStringAsync calls await and the control return to AccessTheWebAsync.
DoIndependentWork invoked.
The program waits the string to be returned (blocks if the operation didn't complete).
return the length of the urlContent.
One thing that took me a while to understand is that the method GetStringAsync runs synchronously despite its name (the name convention is really misleading).
In oreder to run the method asynchronously, we need to use Task.Run or Task.Factory.StartNew explicitly.
But the real question is, if we have independent work, why not do it right away rather then waiting the await to be called from GetStringAsync? (In other words, why async methods doesn't run asynchronously by definition?)
EDIT:
I'll rephrase the second and third operations:
(2) GetStringAsync start synchronously.
(3) In some point, GetStringAsync calls await and the thread forks, the control return to AccessTheWebAsync.
One thing that took me a while to understand is that the method GetStringAsync runs synchronously despite its name (the name convention is really misleading).
That is incorrect. GetStringAsync returns a Task<string>. It will return immediately, which means DoIndependentWork will (potentially) run before the download has completed. The await operator will asynchronously wait until the Task<T> returned by GetStringAsync is done.
But the real question is, if we have independent work, why not do it right away rather then waiting the await to be called from GetStringAsync? (In other words, why async methods doesn't run asynchronously by definition?)
The actual "work" of the asynchronous methods is running after the method has returned. The Task that's returned will (normally) be in a state that's not completed, which means the method is still running asynchronously. You can check Task.IsCompleted to verify.
Try this:
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
Debug.WriteLine("Completed? {0}", getStringTask.IsCompleted); // Will likely print false
DoIndependentWork();
string urlContents = await getStringTask;
Debug.WriteLine("Completed now? {0}", getStringTask.IsCompleted); // Will always print true
Each async method is split into segments on each await. Each segment will become a state on a compiler generated state machine.
Each await instruction works on an awaitable for which a Task is the most common case.
Each state/segment will be executed synchronously until the where the received awaitable is checked if it is already completed.
If the awaitable is completed, it execution will continue on the next state.
If the awaitable is not completed and there isn't a current SynchronizationContext, the execution will be blocked until the the awaitable is completed at which time the execution of the next state will be started.
If a current SynchronizationContext exists, the execution will return to the caller and when the awaitable is completed the continuation to the next state will be posted to the captured SynchronizationContext.
The program waits the string to be returned (blocks if the operation
didn't complete).
await doesn't block on await getStringTask. It will save the internal state of the AccessTheWebAsync method (local variables and where the execution point is) in a compiler-generated state machine object and will return to the outer method which called AccessTheWebAsync. The state will be restored and the execution will be resumed later asynchronously when getStringTask task has become completed, via a compiler-generated continuation callback. If you're familiar with C# iterators and yield keyword, the await state machine control flow is very similar to it, albeit iterators are executed synchronously.
How exactly the execution will be resumed after await depends on the synchronization context of the thread initiating the await. If it's a UI thread pumping Windows messages, the continuation callback will likely be called on the next iteration of the thread's message loop (typically inside Application.Run). If it's a non-UI thread (e.g., a console application), the continuation may happen on a different thread at all. So, while the control flow of your method remains logically linear, technically it is not (as it would have been if you just did getStringTask.Wait() instead of await getStringTask).
The program waits the string to be returned (blocks if the operation didn't complete).
No, it doesn't. await waits, but it doesn't block any threads. That's the whole point.
One thing that took me a while to understand is that the method GetStringAsync runs synchronously despite its name (the name convention is really misleading).
That's wrong. Most of the method does run asynchronously. It most likely also has a small synchronous part at the start, but that should be negligible.
In oreder to run the method asynchronously, we need to use Task.Run or Task.Factory.StartNew explicitly.
No, the method already does run asynchronously. If you want to run the small synchronous part on another thread, then you can use Task.Run(), but that almost never makes any sense. Also, don't use StartNew() for this, it doesn't work well with async methods.
In other words, why async methods doesn't run asynchronously by definition?
A significant point about await is that it resumes on the same context where it left.
This can be very useful in GUI applications, where you often want to modify the UI, then execute the async operation and then modify the UI again. If async automatically meant that the whole method executes on a ThreadPool thread, then that wouldn't be possible.
Also, doing it this way is more efficient, because you don't have to switch to another thread for something that takes very little time.

Categories