请考虑以下使用CancellationTokenSource的基本任务库功能的代码.它启动一个线程,它填充一个字典的价格,并从sql Server数据库读取数据.线程在大约10分钟后结束,每2个小时再次启动,首先调用Cancel,以防线程仍在运行.
private CancellationTokenSource mTokenSource = new CancellationTokenSource(); internal Prices(Dictionary<string,Dealer> dealers) { mDealers = dealers; mTask = Task.Factory.StartNew (() => ReadPrices(mTokenSource.Token),mTokenSource.Token); } internal void Cancel() { mTokenSource.Cancel(); } private void ReadPrices(CancellationToken ct) { using (sqlConnection connection = new sqlConnection(ConfigurationManager.AppSettings["DB"])) { connection.Open(); var dealerIds = from dealer in mDealers.Values where dealer.Id != null select dealer.Id; foreach (var dealerId in dealerIds) { if (!ct.IsCancellationRequested) { FillPrices(connection); } else break; } } }
在某些时候,应用程序在事件日志中遇到以下异常.
Application: Engine.exe Framework Version: v4.0.30319 Description: The
process was terminated due to an unhandled exception. Exception Info:
System.AggregateException Stack: at
System.Threading.Tasks.TaskExceptionHolder.Finalize()
解决方法
任务喜欢听的.这听起来好像不快乐.尽管如此,您可以获得“最后的机会”:
TaskScheduler.UnobservedTaskException += (sender,args) => { foreach (var ex in args.Exception.InnerExceptions) { Log(ex); } args.SetObserved(); };
请注意,这不是解决方案 – 它的目的是让您看到任务正在爆炸以及出现什么错误. SetObserved()将阻止它杀死您的应用程序.但这里的解决方案是理想的:
>不要让你的任务抛出,
>或者确保你在那里检查任务的状态
您的取消检测可能不太满意. IIRC的首选方法是:
foreach(...) { if(ct.IsCancellationRequested) { // any cleanup etc ct.ThrowIfCancellationRequested(); } ... }
或者更简单,如果不需要清理,只需:
foreach(...) { ct.ThrowIfCancellationRequested(); ... }