【问题标题】:Finding out where unobservedTaskException is thrown: stacktrace is null找出抛出 unobservedTaskException 的位置:stacktrace 为 null
【发布时间】:2020-01-06 05:00:08
【问题描述】:

我有一个使用第三方库的大型 C# 应用程序,并且在应用程序的某处运行了一个未等待并引发异常的任务。

所以我在 TaskScheduler.UnobservedTaskException 中添加了一个事件处理程序:

TaskScheduler.UnobservedTaskException += (sender, args) =>
{
    _logger.Error(args.Exception);
    args.SetObserved();
};

但是,当这个处理程序被执行时,我得到了一些堆栈跟踪为 null 的异常:

System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. 
    ---> Grpc.Core.RpcException: Status(StatusCode=Cancelled, Detail="Cancelled")
    --- End of inner exception stack trace ---
---> (Inner Exception #0) Grpc.Core.RpcException: Status(StatusCode=Cancelled, Detail="Cancelled")<---

当我调试这段代码时,args.Exception 的堆栈跟踪为空,我不知道它来自哪里。我尝试使用 Visual Studio 2017 捕获 System.AggregateException 类型的所有异常,但没有一个被捕获。我试图捕获 Grpc.Core.RpcException 类型的所有异常,但是其中很多都被抛出并仅在用户代码中处理(大约每秒 10 个),而我未捕获的异常每隔几个小时才发生一次,所以它是手动跳过应用程序中抛出的所有数千个 RpcExceptions 是不可行的。

我怎样才能知道这个未捕获的异常发生在哪里?我尝试在所有任务/异步方法中添加 try/catch 块,但无济于事,尽管我可能错过了一些。我试图从我的代码中删除所有即发即弃的任务,但我什至不知道这个异常是来自我的代码还是来自外部代码(在这种情况下,我可以向代码的开发人员报告)。

我的应用程序中未等待的异步方法 (async void) 发生在事件处理程序中,我尝试在那里放置 try/catch 块来捕获异常。但是这个问题仍然存在。

我还能做些什么来确定何时何地抛出此异常以及未观察到的任务可能在哪里?

【问题讨论】:

  • async void 是一个红鲱鱼。如果您在async void 方法中有await,并且正在等待抛出的Task,则异常将在线程池上重新抛出,并将关闭您的应用程序。您正在寻找您实际上拥有 aTask 的地方,而该 Task 未被等待(或没有其 .Result 等属性访问权限)
  • @canton7 如果我在 async void 中等待其他任务,并且我用 try/catch 包围该等待,它是否也会被重新抛出?
  • 假设捕获不会重新抛出,不。异常将被吞下。它也不会成为未观察到的任务异常,因为它已被观察到。

标签: c# task-parallel-library .net-4.7


【解决方案1】:

要解决此类问题,您可以使用 dotMemory 之类的内存分析器并收集分配 (https://www.jetbrains.com/help/dotmemory/dotMemory_Profiler_Options.html)!

当发生未处理的异常时,拍摄快照,找到任务(可以通过其类型和 ID 完成)并查看该实例的创建堆栈跟踪 (https://www.jetbrains.com/help/dotmemory/Creation_Stack_Trace_instance.html)。

这里有一些代码可以帮助您入门:

TaskScheduler.UnobservedTaskException += (sender, args) => 
    MessageBox.Show($"Almost there, now take a snapshot and look for the creation stacktrace of {sender.GetType()}, Id={((Task)sender).Id}!");

希望这对你有用,对我有用:)

【讨论】:

猜你喜欢
  • 2011-10-22
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-08
  • 1970-01-01
  • 2022-07-22
  • 1970-01-01
相关资源
最近更新 更多