如果任务等待某事,任务状态将更改为RanToCompletion

这个问题描述了同样的问题 – MSDN Developer Forum 。 这个问题没有得到公认的答案,所给出的任何答案都不能适用于我的案例(因此是一个不同的问题)。

问题也来自我之前提出的问题 ,但是,由于性质和具体问题的不同,我问了一个新问题。

完整代码可以在这里找到: http : //pastebin.com/uhBGWC5e
*唯一改变的是任务完成检查( while – > Task.WhenAll )。


等待任务内部的异步操作时,即使任务仍在运行,任务状态也会更改为RanToCompletion

现在,让我们看看设置:

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

Accept方法:

 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>.Factory.StartNew(Listen, connected).Unwrap(); if (stop == true) { break; } } // Stop the server. server.Stop(); Log("Stoppped {0}", endPoint); } 

由于TaskStatus更改为RanToCompletion, Task.WhenAll().Wait()调用标记本身很快完成,导致程序进一步执行,最终终止。

但是,理论上, Accept任务永远不会停止,它会在明确停止之前监听连接。

这里有什么问题导致Task过早地被标记为RanToCompletion

我可以用更少的代码重现这个问题:

 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"); } 

但这可以正常工作:

 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"); } 

基本上,通过使用Task.Factory.StartNew() ,您将基于生成的单独线程创建一个Task来调用给定的委托( Accept()方法)。 Accept方法本身(就像任何好的async方法一样)实际上会立即返回。 因此,调用它的线程会立即完成其任务,因此创建表示该线程的Task也会立即完成。

如果你允许Accept()返回一个Task而不是void ,那么它返回的Task是你应该等待它等待它运行所有await的时候。

有两件事是错误的: async voidTask.Factory.StartNew 。 这些都是不好的做法。

首先, async void不允许调用代码知道它何时完成 。 所以你在等待并不重要; async void方法将很快返回,并且您的应用程序无法知道Accept实际完成的时间。 要解决此问题,请使用更合适的async Task替换async void

其次, StartNew不了解异步委托 。 StartNew是一个极低级别的API,不应在99.99%的生产代码中使用。 请改用Task.Run

 public static async Task Accept(object state); Task t1 = Task.Run(() => Accept(s1)); Task t2 = Task.Run(() => Accept(s1)); Task.WaitAll(t1, t2);