Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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 my case (hence a different question).

Question is also derived from one I asked previously, but, due to different nature and more specific problem, I'm asking a new one.

Full code can be found here: http://pastebin.com/uhBGWC5e
* Only thing changed is the task completion check (while -> Task.WhenAll).


When awaiting an async operation inside of a Task, the Task status changes to RanToCompletion even though, the Task is still running.

Now, let's see the setup:

// Start async.
Task t1 = Task.Factory.StartNew(Accept, s1);
Task t2 = Task.Factory.StartNew(Accept, s1);

Task.WhenAll(t1, t2).Wait();

The Accept method:

public static async void Accept(object state)
{
    TcpListenerEx server = (TcpListenerEx) state;

    IPEndPoint endPoint = server.LocalEndpoint as IPEndPoint;

    Log("Accepting clients on {0}", endPoint);

    while (true)
    {
        var client = server.AcceptTcpClientAsync();

        if (client == null)
        {
            Log("Null error on accept");
            break;
        }

        TcpClient connected = (TcpClient) client;
        servers[server].Add(connected);

        bool stop = await Task<Task<bool>>.Factory.StartNew(Listen, connected).Unwrap();

        if (stop == true)
        {
            break;
        }
    }

    // Stop the server.
    server.Stop();

    Log("Stoppped {0}", endPoint);
}

Because of TaskStatus changing to RanToCompletion, the Task.WhenAll().Wait() call marks itself finished fairly quickly, resulting in program to be executed further, eventually - terminated.

But, the Accept task, in theory, should never stop, it's listening for connections until explicitly stopped.

What is the problem here that's causing the Task to be marked as RanToCompletion prematurely?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
802 views
Welcome To Ask or Share your Answers For Others

1 Answer

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 awaits.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...