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.SetResultruns itsTaskcontinuations synchronously (in most cases).This means that in your case, everything after
await tcs.Taskand up to the nextawaitwill run before theevtFinished.Set()is even reached.There are multiple way to solve this, but the easiest one will be to pass the
TaskContinuationOptions.RunContinuationsAsynchronouslyflag to theTaskCompletionSourceconstructor.