I run several tasks and keep them in a list to check if they are already completed.
I discovered that tasks that come from an async
method are always shown as RanToCompletion
although the task itself was still running.
Is there a way to get the "is complete" information from a Task
object in both cases?
Here's a simple test case that shows this behaviour. I run two tasks, with/without an async
method and check the states during and after completion.
private void test()
{
;
Action actionAsync = funcAsync;
Task taskAsync = Task.Run(actionAsync);
Action action = func;
Task task = Task.Run(action);
var statusAsync = taskAsync.Status;
var status = task.Status;
// stati are either WaitingToRun or Running
Thread.Sleep(TimeSpan.FromSeconds(2));
// Now it's quite certain, that both have started
var statusAsync2 = taskAsync.Status;
var status2 = task.Status;
Debug.Assert(statusAsync2 == TaskStatus.RanToCompletion);
Debug.Assert(status2 == TaskStatus.Running);
;
Thread.Sleep(TimeSpan.FromSeconds(12));
// Now it's quite certain, that both have finished
var statusAsync3 = taskAsync.Status;
var status3 = task.Status;
;
Debug.Assert(statusAsync3 == TaskStatus.RanToCompletion);
Debug.Assert(status3 == TaskStatus.RanToCompletion);
}
private async void funcAsync()
{
await Task.Delay(TimeSpan.FromSeconds(10));
}
private void func()
{
Thread.Sleep(TimeSpan.FromSeconds(10));
}
I discovered that tasks that come from an async method are always shown as RanToCompletion although the task itself was still running.
Yes, because your void
method has completed, and that's all that Task.Run
is calling. If instead you use:
private async Task FuncAsync()
{
await Task.Delay(TimeSpan.FromSeconds(10));
}
and use Func<Task>
instead Action
, then you'll call Task.Run(Func<Task>)
and all will be well.
Short but complete example:
using System;
using System.Threading;
using System.Threading.Tasks;
class Test
{
static void Main()
{
Func<Task> func = FuncAsync;
Task task = Task.Run(func);
for (int i = 0; i < 7; i++)
{
Console.WriteLine(task.Status);
Thread.Sleep(1000);
}
}
private static async Task FuncAsync()
{
await Task.Delay(TimeSpan.FromSeconds(5));
}
}
Output:
WaitingForActivation
WaitingForActivation
WaitingForActivation
WaitingForActivation
WaitingForActivation
RanToCompletion
RanToCompletion
Try to avoid writing void
async methods if you possibly can. They should basically only be used for event handlers.
See more on this question at Stackoverflow