Monitoring Task completion

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));
}
Jon Skeet
people
quotationmark

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.

people

See more on this question at Stackoverflow