The question describes the same problem found here - MSDN Developer Forum. The question does not have an accepted answer, neither any of the answers given can be applied to
There are two things wrong: async void and Task.Factory.StartNew. Both of these are bad practices.
First, async void does not allow the calling code to know when it completes. So it doesn't matter that you're waiting; the async void
method will return fairly quickly, and your app can't know when Accept
actually finishes. To fix this, replace async void
with the much more proper async Task
.
Second, StartNew doesn't understand asynchronous delegates. StartNew
is an extremely low-level API that should not be used in 99.99% of production code. Use Task.Run
instead.
public static async Task Accept(object state);
Task t1 = Task.Run(() => Accept(s1));
Task t2 = Task.Run(() => Accept(s1));
Task.WaitAll(t1, t2);
I can reproduce this issue with far less code:
void Main()
{
Task t1 = Task.Factory.StartNew(Accept);
t1.Wait();
Console.WriteLine("Main ended");
}
public static async void Accept()
{
while (true)
{
await Task.Delay(1000);
}
Console.WriteLine("Stoppped");
}
But this works correctly:
void Main()
{
Task t1 = Accept();
t1.Wait();
Console.WriteLine("Main ended");
}
public static async Task Accept()
{
while (true)
{
await Task.Delay(1000);
}
Console.WriteLine("Stoppped");
}
Basically, by using Task.Factory.StartNew()
, you are creating a Task
based on a separate thread getting spawned to invoke the given delegate (the Accept()
method). The Accept
method itself (like any good async
method) actually returns immediately. So the thread that calls it finishes its task immediately, so the Task
created to represent that thread also finishes immediately.
If you allow Accept()
to return a Task
instead of void
, then the Task
that it returns is what you should be awaiting if you want to wait until it has run through all its await
s.