Rule Definition
According to the MSDN documentation:
The root cause of this deadlock is due to the way await handles contexts. By default, when an incomplete Task is awaited, the current “context” is captured and used to resume the method when the Task completes. This “context” is the current SynchronizationContext unless it’s null, in which case it’s the current TaskScheduler. GUI and ASP.NET applications have a SynchronizationContext that permits only one chunk of code to run at a time. When the await completes, it attempts to execute the remainder of the async method within the captured context. But that context already has a thread in it, which is (synchronously) waiting for the async method to complete. They’re each waiting for the other, causing a deadlock.
Remediation
In an asynchronous method:
- To retrieve the result of a background task don't use "Task.Wait, Task.Result" or "Task.GetAwaiter.GetResult" but use "await"
- To wait for any task to complete don't use "Task.WaitAny" but use "await Task.WhenAny"
- To retrieve the results of multiple tasks don't use "Task.WaitAll" but use "await Task.WhenAll"
- To wait a period of time don't use "Thread.Sleep" but use "await Task.Delay"
Violation Code Sample
public static class DeadlockDemo
{
private static async Task DelayAsync()
{
await Task.Delay(1000);
}
// This method causes a deadlock when called in a GUI or ASP.NET context.
public static void Test()
{
// Start the delay.
var delayTask = DelayAsync();
// Wait for the delay to complete.
delayTask.Wait(); // VIOLATION
}
}
Fixed Code Sample
public static class DeadlockDemo
{
private static async Task DelayAsync()
{
await Task.Delay(1000);
}
// This method causes a deadlock when called in a GUI or ASP.NET context.
public static void Test()
{
// Start the delay.
var delayTask = DelayAsync();
// Wait for the delay to complete.
await delayTask; // NO VIOLATION
}
}
Reference
https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
Related Technologies
Technical Criterion
CWE-1088 - Synchronous Access of Remote Resource without Timeout
About CAST Appmarq
CAST Appmarq is by far the biggest repository of data about real IT systems. It's built on thousands of analyzed applications, made of 35 different technologies, by over 300 business organizations across major verticals. It provides IT Leaders with factual key analytics to let them know if their applications are on track.