运行System.Threading.Tasks.Task时出现异常

Ser*_*sen 9 .net c# task task-parallel-library

请考虑以下代码,该代码使用带有CancellationTokenSource的基本任务库功能.它启动一个线程,用字符填充字典并从SQL服务器数据库中读取数据.线程在大约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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,在某些时候,应用程序在事件日志中崩溃并出现以下异常.

应用程序:Engine.exe Framework版本:v4.0.30319描述:由于未处理的异常,进程已终止.异常信息:System.AggregateException Stack:at System.Threading.Tasks.TaskExceptionHolder.Finalize()

它必须与这里的代码有关,因为在其他任何地方都没有使用Tasks库,但我无法弄清楚代码有什么问题.有没有人知道这里有什么问题?

Mar*_*ell 19

任务喜欢倾听.听起来有点不开心.尽管如此,你确实得到了"最后的机会"来听取它:

TaskScheduler.UnobservedTaskException += (sender, args) =>
{
    foreach (var ex in args.Exception.InnerExceptions)
    {
        Log(ex);
    }            
    args.SetObserved();
};
Run Code Online (Sandbox Code Playgroud)

请注意,这不是作为修复程序 - 它旨在让您了解Task爆炸的内容和错误.这SetObserved()将防止它杀死您的应用程序.但理想的解决方法是:

  • 不要让你的任务抛出,
  • 或确保您以后检查任务的状态

你的取消检测很可能不满意.IIRC这样做的首选方式是:

foreach(...) {
    if(ct.IsCancellationRequested) {
        // any cleanup etc
        ct.ThrowIfCancellationRequested();
    } 
    ...
}
Run Code Online (Sandbox Code Playgroud)

或者更简单地说,如果不需要清理,只需:

foreach(...) {
    ct.ThrowIfCancellationRequested();
    ...
}
Run Code Online (Sandbox Code Playgroud)

同样,它可能只是一个数据访问异常.有任意数量的与一个数据库时可能发生的异常.超时,死锁,无法连接等