While running the following C# program, I randomly got two different results. Result 1 (occurred frequently) is actually deadlocked. Please explain to me why this happened. I am not expecting the deadlock while using WaitOne on AutoResetEvent.
class Program
{
static async Task Main()
{
TaskCompletionSource<bool> tcs = new();
AutoResetEvent evtFinished = new AutoResetEvent(false);
Func<Task> func = async Task () =>
{ await Task.Delay(10); tcs.SetResult(true); evtFinished.Set(); };
var t = func.Invoke();
//await func.Invoke();
await tcs.Task;
if (evtFinished.WaitOne(1000))
Console.WriteLine("First Wait OK");
else
{
Console.WriteLine("First Wait Timeout");
for (int i = 0; i < 10 && !evtFinished.WaitOne(100); i++)
Console.WriteLine($" {i+1} Wait Timeout");
await t;
evtFinished.WaitOne();
Console.WriteLine("Wait OK");
}
}
}
<<<<<Result 1: >>>>>>
# First Wait Timeout
# 1 Wait Timeout
# 2 Wait Timeout
# 3 Wait Timeout
# 4 Wait Timeout
# 5 Wait Timeout
# 6 Wait Timeout
# 7 Wait Timeout
# 8 Wait Timeout
# 9 Wait Timeout
# 10 Wait Timeout
# Wait OK
<<<<<Result2 >>>>>
# First Wait OK
By default,
TaskCompletionSource.SetResult
runs itsTask
continuations synchronously (in most cases).This means that in your case, everything after
await tcs.Task
and up to the nextawait
will run before theevtFinished.Set()
is even reached.There are multiple way to solve this, but the easiest one will be to pass the
TaskContinuationOptions.RunContinuationsAsynchronously
flag to theTaskCompletionSource
constructor.