C# .NET6中线程内使用await导致线程中断的问题
问题分析:自定义线程内用await后后续代码没执行
问题说明
在.NET 6无Main函数的新式控制台应用里,自定义线程里的异步函数走到await那一行时,线程直接提前结束,[3]段代码完全没执行,实际跑出来的顺序是[1][2][4],和预期的[1][2][3][4]对不上。
测试代码
public class Question { public static async Task<double> testTask() { // [2] await Task.Run(() => { Console.WriteLine("start testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId); for (int i = 0; i < 100; i++) { Task.Delay(10).Wait(); } Console.WriteLine("end testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId); }); return 42.00; } static async Task ThreadFunction() { Console.WriteLine("ThreadFunction begin tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId); // [1] //double x = await test.testTask().ConfigureAwait(true); double x = await test.testTask(); int inserted = 0; for (long i = 0; i < 100; i++) System.Threading.Thread.Sleep(100); // [3] Console.WriteLine("ThreadFunction end tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId); } public static void startTestThread() { Console.WriteLine("start startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId); Thread TestThread = new Thread(() => ThreadFunction()); TestThread.Start(); TestThread.Join(); // [4] Console.WriteLine("end startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId); } }
为啥会这样
- Thread不兼容异步方法:
Thread的启动委托是无返回值的同步类型,你把async Task的ThreadFunction塞进去,相当于把它当成async void来执行——完全忽略了它返回的Task,根本不会等异步方法做完。 - 异步方法的提前返回特性:异步方法碰到第一个还没完成的
await时,会立刻返回一个未完成的Task,然后让出当前线程。Thread看到委托执行到返回这一步,就认为任务完成了,直接把TestThread给终止了。 - 进程终止导致后续代码没机会跑:
await之后的[3]段代码,本来会被调度到线程池的某个线程上继续执行,但主线程已经通过TestThread.Join()等完了TestThread,接着就执行[4]然后结束整个进程,线程池的代码还没来得及执行,进程就没了,所以[3]根本跑不起来。
怎么改
- 别用
Thread跑异步方法,改用Task.Run配合await来等待任务完成(这是异步编程的正确姿势):public static async Task startTestThread() { Console.WriteLine("start startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId); await Task.Run(() => ThreadFunction()); Console.WriteLine("end startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId); } - 要是非得用
Thread,那就得同步等待异步方法完成(不推荐,会阻塞线程,失去异步的意义):Thread TestThread = new Thread(() => ThreadFunction().GetAwaiter().GetResult());
内容的提问来源于stack exchange,提问作者nullptr
相关产品推荐
相关产品推荐

