await vs Task.Wait - Deadlock?
Wait
and await
- while similar conceptually - are actually completely different.
Wait
will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async
all the way down"; that is, don't block on async
code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await
will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await
expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Wait
ing on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait
cannot execute the Delay
task inline because there's no code for it).
You may find my async
/ await
intro helpful.
Using Task.Wait instead of await for async programming
Isn't that technically incorrect then?
No, because it's being very specific. It's not saying that writing an async
method that awaits a task is always the same as just synchronously waiting on that task, it's only referring to very specifically the case of an async
Main
method as an entry point for the application. When you make the Main
method async
, it just synchronously waits on the returned task, making it functionally equivalent to just synchronously waiting on the task inside the method instead of making the method async
only in that one exact situation.
(You could also make an argument that's it's just trying to say that StartNew
with the parameters provided and Run
are equivalent, and isn't intending to refer to the difference between the method being async versus synchronously waiting.)
why would ASP.Net allow a synchronous Wait on them anyway?
Task
wasn't created exclusively to be a representation of work done asynchronously. It was designed to do that and also to synchronously work in parallel using multiple threads. When you're using tasks for asynchrony, you should basically never be using Wait
or other synchronous blocking mechanism, but if you're using it to do multithreaded work synchronously, it's useful. You could make a [good] argument that they should have kept those concepts separate, but they didn't, and it's way too late to change it now.
Doesn't that kind of violate their main utility?
Yes, yes it does. Which is why I'm not a fan of this implementation, and would have preferred they'd implemented it differently. But they didn't.
The article should explain the differences between the two calls clearly.
Yes it should.
Task.Wait() deadlocks my application
I have read that it is beneficial to use async/await on networking
Yes, but why?
The answer is: async
is beneficial (especially for I/O-based code) so that you free up threads to do other things. In an ASP.NET app, this means you have more threads available to handle incoming requests. Oh, wait...
protected override void Seed(ApplicationDbContext context)
When your application is handling its first request (and seeding the db), there isn't any point in freeing up threads because they won't be able to do anything until after the db is seeded anyway.
So in this situation, you should just synchronously upload.
can someone explain why this is happening
I have a blog post that goes into more detail, but to summarize:
await
by default will capture a "context", and will resume executing theasync
method in that context.- ASP.NET (currently) has a request context that handles things like
HttpContext.Current
, the current page culture, etc. - The ASP.NET context only allows one thread in at a time.
Thus, when you block a thread in the request context (Wait
), the async
method cannot complete because it's waiting for that request context to be free. Of course, the Wait
is waiting for the async
method to complete, so you end up with a deadlock.
DeadLock on task.Wait() with Task which edit UI
You have a deadlock because ping.Wait();
blocks UI thread.
You should wait for task asynchronously using await
.
So, if Stop()
is event handler then change it to:
public async void Stop() // async added here
{
if (running)
{
tokenSource.Cancel();
await ping; // await here
ping.Dispose();
tokenSource.Dispose();
}
running = false;
}
If it is not:
public async Task Stop() // async added here, void changed to Task
{
if (running)
{
tokenSource.Cancel();
await ping; // await here
ping.Dispose();
tokenSource.Dispose();
}
running = false;
}
As mentioned by @JohnB async methods should have Async
suffix so, the method should be named as StopAsync()
.
Similar problem and solution are explained here - Do Not Block On Async Code
You should avoid synchronous waiting on tasks, so you should always use await
with tasks instead of Wait()
or Result
. Also, as pointed by @Fildor you should use async-await
all the way to avoid such situations.
Deadlock with async Task.Run method with Wait from Synchronus method and timeout
You are deadlocking the application because you didn't use async
/await
or ConfigureAwait(false
) but you chose to use Task.Wait
and Task.Result
instead.
You should know first that Task.Run
captures the SynchronizationContext
of the thread it is executed on. Then Task.Run
runs on a new ThreadPool
thread. When completed it will return to the parent thread to continue execution of the remaining code. When returning it will return to the captured SyncronizationContext
. You are breaking the concept by using Task.Wait
and Task.Result
. Both Task
members will invoke the Task
synchronously, which means the parent thread will block itself until the child thread has completed. The child thread completes but the Task
can't return to the captured SynchronizationContext
to execute the remaining code (the code after Task.Wait
), since the parent thread is still blocking itself by waiting for the task to run to completion.
Because you used Task.Wait
in one place and Task.Result
in another, you have created two potential deadlock situations:
Let's step through the Function()
code:
public Task<ReturnsMessage> Function() {
1) Create a task and start it:
var task = Task.Run(
() =>
{
var result = SyncMethod();
return new ReturnMessage(result);
});
Important things do happen here:Task.Run
captures the current SynchronizationContext
and starts execution in the background while the parent thread continues to execute. (If await
would've been used here, then the remaining code that follows the await
would be enqueued into a continuation queue for later execution. The intend is that the current thread can return (leave the current context) so that it doesn't need to wait and block. Remaining code will be executed by Task
once the child thread has run to completion, since it was enqueued in the continuation queue before).
2) task.Wait()
waits until the background thread has completed. Waiting means blocking the thread from continue to execute. The call stack is parked. This is equal to synchronization of the background thread, since there is no parallel execution anymore as the parent thread doesn't continue to execute but blocks:
// Dangerous implementation of a timeout for the executing `task` object
if (task.Wait(delay)) {
return task;
}
Important things do happen here:task.Wait()
blocks the current thread (SynchronizationContext
) waiting for the child thread to complete. The child task completes and Task
tries to execute the previously enqueued remaining code from the continuation queue in the captured SynchronizationContext
. But this context is blocked by the thread waiting for the child task to complete. Potential deadlock situation one.
The following remaining code will be unreachable:
var tcs = new TaskCompletionSource<ReturnMessage>();
tcs.SetCanceled();
return tcs.Task;
async
and await
was introduced to get rid of the blocking waits. await
allows the parent thread to return and continue. The remaining code after await
will be executed as continuation in the captured SynchronizationContext
.
This is the fix for the first deadlock also using a proper task timeout solution that uses Task.WhenAny
(not preferred):
public async Task<ReturnsMessage> FunctionAsync()
{
using (var cancellationTokenSource = new CancellationTokenSource())
{
try
{
var task = Task.Run(
() =>
{
// Check if the task needs to be cancelled
// because the timeout task ran to completion first
cancellationToken.ThrowIfCancellationRequested();
var result = SyncMethod();
return result;
}, cancellationTokenSource.Token);
int delay = 500;
Task timoutTask = Task.Delay(delay, cancellationTokenSource.Token);
Task firstCompletedTask = await Task.WhenAny(task, timoutTask);
if (firstCompletedTask == task)
{
// The 'task' has won the race, therefore
// cancel the 'timeoutTask'
cancellationTokenSource.Cancel();
return await task;
}
}
catch (OperationCanceledException)
{}
// The 'timeoutTask' has won the race, therefore
// cancel the 'task' instance
cancellationTokenSource.Cancel();
var tcs = new TaskCompletionSource<string>();
tcs.SetCanceled();
return await tcs.Task;
}
}
Or the fix for the first deadlock with an alternate and much better timeout approach using the CancellationTokenSouce
timeout constructor overload (preferred):
public async Task<ReturnsMessage> FunctionAsync()
{
var timeout = 50;
using (var timeoutCancellationTokenSource = new CancellationTokenSource(timeout))
{
try
{
return await Task.Run(
() =>
{
// Check if the timeout elapsed
timeoutCancellationTokenSource.Token.ThrowIfCancellationRequested();
var result = SyncMethod();
return result;
}, timeoutCancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
var tcs = new TaskCompletionSource<string>();
tcs.SetCanceled();
return await tcs.Task;
}
}
}
The second potential deadlocking code is the consumption of Function()
:
for (var i = 0; i < maxAttempts; i++)
{
return Function().Result;
}
From Microsoft Docs:
Accessing the property's [
Task.Result
] get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.
The reason for the deadlocking is the same as explained before: a blocked SynchronizationContext
that prevents the execution of the scheduled continuation.
To fix the second deadlock we can use async/await (preferred) or ConfigreAwait(false)
:
for (var i = 0; i < maxAttempts; i++)
{
return await FunctionAsync();
}
or ConfigreAwait(false)
. This approach can be used to force synchronized execution of an asynchronous method:
for (var i = 0; i < maxAttempts; i++)
{
return FunctionAsync().ConfigureAwait(false).GetAwaiter().GetResult();
}
ConfigreAwait(false)
instructs the Task
to ignore the captured SynchronizationContext
and to continue the execeution of the continuation queue on another ThreadPool
thread which will never be the parent thread.
Trying to understand Async/Await but seem to get deadlock c#
I had to put await on the CalculateInvoice method for it to move on.
[HttpPost]
[Route("calculateInvoice")]
public async Task<IHttpActionResult> CalculateInvoice([FromBody] InvoiceRequestModel model)
{
model.EmailAddress = AccountHelper.GetLoggedInUsername();
var result = await _paymentHandler.CreatePaymentsAndSendAsEmail(model, true);
if (result == null)
return Conflict();
return Ok(result);
}
async/await deadlock when using WindowsFormsSynchronizationContext in a console app
This happens because the WindowsFormsSynchronizationContext
depends on the existence of a standard Windows message loop. A console application does not start such a loop, so the messages posted to the WindowsFormsSynchronizationContext
are not processed, the task continuations are not invoked, and so the program hangs on the first await
. You can confirm the non-existence of a message loop by querying the boolean property Application.MessageLoop
.
Gets a value indicating whether a message loop exists on this thread.
To make the WindowsFormsSynchronizationContext
functional you must start a message loop. It can be done like this:
static void Main(string[] args)
{
EventHandler idleHandler = null;
idleHandler = async (sender, e) =>
{
Application.Idle -= idleHandler;
await MyMain(args);
Application.ExitThread();
};
Application.Idle += idleHandler;
Application.Run();
}
The MyMain
method is your current Main
method, renamed.
Update: Actually the Application.Run
method installs automatically a WindowsFormsSynchronizationContext
in the current thread, so you don't have to do it explicitly. If you want you can prevent this automatic installation, be configuring the property WindowsFormsSynchronizationContext.AutoInstall
before calling Application.Run
.
The
AutoInstall
property determines whether theWindowsFormsSynchronizationContext
is installed when a control is created, or when a message loop is started.
Related Topics
How to Specify a [Dllimport] Path At Runtime
Post an HTML Table to Ado.Net Datatable
Difference Between String and String in C#
What's Wrong With Using Thread.Abort()
All Possible Array Initialization Syntaxes
Interaction Between Forms - How to Change a Control of a Form from Another Form
What Are the Correct Version Numbers For C#
Convert Integer to Hexadecimal and Back Again
How to Start a Process from C#
Json.Net: How to Deserialize Without Using the Default Constructor
Possible to Call C++ Code from C#
Linq'S Distinct() on a Particular Property
How to Do Impersonation in .Net
How to Find the Method That Called the Current Method
Convert Generic List/Enumerable to Datatable
Type Checking: Typeof, Gettype, or Is
Any Difference Between "Await Task.Run(); Return;" and "Return Task.Run()"