Table of Contents

VSTHRD002 Avoid problematic synchronous waits

Synchronously waiting on Task, ValueTask, or awaiters is dangerous and may cause dead locks.

Examples of patterns that are flagged by this analyzer

void DoSomething()
{
    DoSomethingElseAsync().Wait();
    DoSomethingElseAsync().GetAwaiter().GetResult();
    var result = CalculateSomethingAsync().Result;
}

Solution

Please consider the following options:

  1. Switch to asynchronous wait if the caller is already a "async" method.
  2. Change the chain of callers to be "async" methods, and then change this code to be asynchronous await.
  3. Use JoinableTaskFactory.Run() to wait on the tasks or awaiters.
async Task DoSomethingAsync()
{
    await DoSomethingElseAsync();
    await DoSomethingElseAsync();
    var result = await CalculateSomethingAsync();
}

void DoSomething()
{
    joinableTaskFactory.Run(async delegate
    {
        await DoSomethingElseAsync();
        await DoSomethingElseAsync();
        var result = await CalculateSomethingAsync();
    });
}

Accessing a task's result is not reported when the analyzer can prove the task has completed. Recognized proofs include awaiting the task (directly or through Task.WhenAll), guarding the access with a completion property such as IsCompletedSuccessfully, and awaiting the task in the negative branch of such a guard.

VSTHRD002 can also report project-specific synchronous blocking methods configured in vs-threading.SyncBlockingMethods.txt. See Analyzer Configuration.

Refer to Asynchronous and multithreaded programming within VS using the JoinableTaskFactory for more information.