Async always WaitingForActivation

Viewed 136710

I am trying to figure out what the async & await keywords are all about, however the output isn't what I'm expecting.

The console application is as follows:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Foo called");
        var result = Foo(5);

        while (result.Status != TaskStatus.RanToCompletion)
        {
            Console.WriteLine("Thread ID: {0}, Status: {1}", Thread.CurrentThread.ManagedThreadId, result.Status);
            Task.Delay(100).Wait();
        }

        Console.WriteLine("Result: {0}", result.Result);
        Console.WriteLine("Finished.");
        Console.ReadKey(true);
    }

    private static async Task<string> Foo(int seconds)
    {
        return await Task.Run(() =>
            {
                for (int i = 0; i < seconds; i++)
                {
                    Console.WriteLine("Thread ID: {0}, second {1}.", Thread.CurrentThread.ManagedThreadId, i);
                    Task.Delay(TimeSpan.FromSeconds(1)).Wait();
                }

                return "Foo Completed.";
            });
    }
}

The output is:

Foo called
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 0.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 1.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 2.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 3.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 6, second 4.
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Thread ID: 10, Status: WaitingForActivation
Result: Foo Completed.
Finished..

I was expecting to see the status changing from WaitingForActivation once the method is started.

How can it stay in this state and be active?

5 Answers

I had the same problem. The answers got me on the right track. So the problem is that functions marked with async don't return a task of the function itself as expected (but another continuation task of the function).

So its the "await"and "async" keywords that screws thing up. The simplest solution then is simply to remove them. Then it works as expected. As in:

static void Main(string[] args)
{
    Console.WriteLine("Foo called");
    var result = Foo(5);

    while (result.Status != TaskStatus.RanToCompletion)
    {
        Console.WriteLine("Thread ID: {0}, Status: {1}", Thread.CurrentThread.ManagedThreadId, result.Status);
        Task.Delay(100).Wait();
    }

    Console.WriteLine("Result: {0}", result.Result);
    Console.WriteLine("Finished.");
    Console.ReadKey(true);
}

private static Task<string> Foo(int seconds)
{
    return Task.Run(() =>
    {
        for (int i = 0; i < seconds; i++)
        {
            Console.WriteLine("Thread ID: {0}, second {1}.", Thread.CurrentThread.ManagedThreadId, i);
            Task.Delay(TimeSpan.FromSeconds(1)).Wait();
        }

        return "Foo Completed.";
    });
}

Which outputs:

Foo called
Thread ID: 1, Status: WaitingToRun
Thread ID: 3, second 0.
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 3, second 1.
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 3, second 2.
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 3, second 3.
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 3, second 4.
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Thread ID: 1, Status: Running
Result: Foo Completed.
Finished.

this code seems to have address the issue for me. it comes for a streaming class, ergo some of the nomenclature.

''' <summary> Reference to the awaiting task. </summary>
''' <value> The awaiting task. </value>
Protected ReadOnly Property AwaitingTask As Threading.Tasks.Task

''' <summary> Reference to the Action task; this task status undergoes changes. </summary>
Protected ReadOnly Property ActionTask As Threading.Tasks.Task

''' <summary> Reference to the cancellation source. </summary>
Protected ReadOnly Property TaskCancellationSource As Threading.CancellationTokenSource

''' <summary> Starts the action task. </summary>
''' <param name="taskAction"> The action to stream the entities, which calls
'''                           <see cref="StreamEvents(Of T)(IEnumerable(Of T), IEnumerable(Of Date), Integer, String)"/>. </param>
''' <returns> The awaiting task. </returns>
Private Async Function AsyncAwaitTask(ByVal taskAction As Action) As Task
    Me._ActionTask = Task.Run(taskAction)
    Await Me.ActionTask '  Task.Run(streamEntitiesAction)
    Try
        Me.ActionTask?.Wait()
        Me.OnStreamTaskEnded(If(Me.ActionTask Is Nothing, TaskStatus.RanToCompletion, Me.ActionTask.Status))
    Catch ex As AggregateException
        Me.OnExceptionOccurred(ex)
    Finally
        Me.TaskCancellationSource.Dispose()
    End Try
End Function

''' <summary> Starts Streaming the events. </summary>
''' <exception cref="InvalidOperationException"> Thrown when the requested operation is invalid. </exception>
''' <param name="bucketKey">            The bucket key. </param>
''' <param name="timeout">              The timeout. </param>
''' <param name="streamEntitiesAction"> The action to stream the entities, which calls
'''                                     <see cref="StreamEvents(Of T)(IEnumerable(Of T), IEnumerable(Of Date), Integer, String)"/>. </param>
Public Overridable Sub StartStreamEvents(ByVal bucketKey As String, ByVal timeout As TimeSpan, ByVal streamEntitiesAction As Action)
    If Me.IsTaskActive Then
        Throw New InvalidOperationException($"Stream task is {Me.ActionTask.Status}")
    Else
        Me._TaskCancellationSource = New Threading.CancellationTokenSource
        Me.TaskCancellationSource.Token.Register(AddressOf Me.StreamTaskCanceled)
        Me.TaskCancellationSource.CancelAfter(timeout)
        ' the action class is created withing the Async/Await function
        Me._AwaitingTask = Me.AsyncAwaitTask(streamEntitiesAction)
    End If
End Sub

I overcome this issue with if anybody interested. In myMain method i called my readasync method like

Dispatcher.BeginInvoke(new ThreadStart(() => ReadData()));

Everything is fine for me now.

Related