C#异步灯泡生产模拟程序在await处崩溃,求故障原因
问题原因与修复方案
核心崩溃原因
主线程未正确等待异步入口方法
代码最开头直接调用Main();但未使用await,而Main是async Task类型,这会导致主线程不等待异步操作完成就继续执行,当程序执行到await Task.WhenAny(taskList)时,主线程可能提前退出,引发程序无提示终止。生产循环无限执行
startMaschine方法中的while(i<10000)循环体内没有i++语句,导致任务永远无法完成。当用户输入选项2时,Task.WhenAny会一直等待永远不会结束的任务,结合主线程未等待的问题,直接触发程序终止。Random类线程安全问题
多个异步任务共用同一个Random实例,而Random并非线程安全类型,多线程环境下调用Next()会导致其内部状态损坏,可能抛出未捕获的异常,进一步导致程序崩溃。
次要功能问题
每次输入选项1启动机器时,都会调用prod.registerObserver(new Observer()),导致Production实例中累积多个Observer,后续检测到次品时会重复打印通知信息。
修复后的完整代码
using System; using System.Collections.Generic; using System.Threading.Tasks; namespace BulbProduction { class Program { static async Task Main() { Console.WriteLine("Bulb Production Monitoring!"); List<Task<string>> taskList = new List<Task<string>>(); string input = ""; int maschineID = 1; Production prod = new Production(); // 仅注册一次Observer,避免重复通知 prod.registerObserver(new Observer()); Console.WriteLine("1: starts a production maschine"); Console.WriteLine("2: analyses the results"); Console.WriteLine("3: exits the production process"); while (!input.Equals("exit")) { input = Console.ReadLine(); switch (input) { case "1": // 每个任务使用独立的Random实例,避免线程安全问题 Random rndGenerator = new Random(); taskList.Add(prod.startMaschine(maschineID, rndGenerator)); maschineID++; break; case "2": while (taskList.Any()) { Task<string> finishedTask = await Task.WhenAny(taskList); // 安全获取结果,处理可能的异常 try { string result = await finishedTask; Console.WriteLine(result); } catch (Exception ex) { Console.WriteLine($"Task failed: {ex.Message}"); } taskList.Remove(finishedTask); } break; case "3": input = "exit"; break; default: break; } } } } public class Bulb { public bool _functionTest; } public class Production { private List<Observer> _observerList = new List<Observer>(); public async Task<string> startMaschine(int maschineId, Random rndGenerator) { return await Task.Run(async () => { Console.WriteLine($"Maschine {maschineId} is ready for use ... "); int i = 0; int defect = 0; // 添加i++,让循环正常结束 while (i < 10000) { int rndNumber = rndGenerator.Next(1, 101); Bulb bulb = new Bulb(); await Task.Delay(50); if (rndNumber <= 5) { bulb._functionTest = false; defect++; this.notify(maschineId); } else { bulb._functionTest = true; } i++; } return $"Maschine {maschineId} has produced {defect} defective bulbs."; }); } public void registerObserver(Observer obs) { _observerList.Add(obs); } private void notify(int maschineId) { foreach (Observer obs in _observerList) { obs.update(maschineId); } } } public class Observer { public void update(int maschineId) { DateTime localDate = DateTime.Now; Console.WriteLine($"Defect bulb identified on maschine {maschineId} at {localDate}."); } } }
关键修复点说明
- 移除了手动调用
Main()的代码,让异步Main作为程序入口,确保主线程等待所有异步操作。 - 在生产循环中添加
i++,保证任务能正常完成并返回结果。 - 每次启动机器时创建独立的
Random实例,避免多线程安全问题;也可以使用Random.Shared(.NET Core 3.0+)替代。 - 仅注册一次Observer,避免重复打印次品通知。
- 添加了异常捕获逻辑,处理任务执行中可能出现的异常,避免程序意外崩溃。
内容的提问来源于stack exchange,提问作者Z.J
相关产品推荐
相关产品推荐

