All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.plugins.csharp.S4462.html Maven / Gradle / Ivy

There is a newer version: 10.4.0.108396
Show newest version

Why is this an issue?

Making blocking calls to async methods transforms code that was intended to be asynchronous into a blocking operation. Doing so can cause deadlocks and unexpected blocking of context threads.

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.

To Do This … Instead of This … Use This

Retrieve the result of a background task

Task.Wait, Task.Result or Task.GetAwaiter.GetResult

await

Wait for any task to complete

Task.WaitAny

await Task.WhenAny

Retrieve the results of multiple tasks

Task.WaitAll

await Task.WhenAll

Wait a period of time

Thread.Sleep

await Task.Delay

Noncompliant code example

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(); // Noncompliant
    }
}

Compliant solution

public static class DeadlockDemo
{
    private static async Task DelayAsync()
    {
        await Task.Delay(1000);
    }

    public static async Task TestAsync()
    {
        // Start the delay.
        var delayTask = DelayAsync();
        // Wait for the delay to complete.
        await delayTask;
    }
}

Exceptions

  • Main methods of Console Applications are not subject to this deadlock issue and so are ignored by this rule.
  • Thread.Sleep is also ignored when it is used in a non-async method.
  • Calls chained after Task.Run or Task.Factory.StartNew are ignored because they don’t suffer from this deadlock issue

Resources





© 2015 - 2025 Weber Informatics LLC | Privacy Policy