【问题标题】:Spoofing the call stack inside a worker thread that processes queued tasks在处理排队任务的工作线程内欺骗调用堆栈
【发布时间】:2017-10-26 00:21:07
【问题描述】:

假设我有一个带有输入Queue<Task> 的工作线程,它在一个连续的while 循环内进行处理。每当外部代码将新的Task 存入队列时,worker 就会醒来并等待任务实例。但是,如果引发异常,我想记录详细信息,包括完整的调用堆栈,以便确定应归咎于哪个代码路径。

不幸的是,异常的调用堆栈植根于工作线程内部。这是可以理解的 - 它是执行任务的最根代码。

问题是:我是否可以假设将异常的调用堆栈与最初将任务放入工作线程队列的调用堆栈合并?

我知道我可以手动执行此操作,只需通过 Environment.StackTrace 记下存放调用堆栈并将其与异常一起记录到 worker 中。但这仍然是我必须跟踪的两个独立堆栈。

是否有更聪明的方法来欺骗异常自身的调用堆栈,使其看起来好像是连续的?因为它有点像 - 任务入队和出队时点之间只有一点延迟。

编辑:我基本上是在寻找一种方法来做 C# 的 async 对调用堆栈所做的事情(即将它们合并到发生的所有线程跃点上),仅在下面的常规线程内我的控制。

【问题讨论】:

  • ExceptionDispatchInfo.Throw() 会是答案吗? "异常被抛出,就好像它从捕获它的点流到调用 Throw 方法的点一样。"
  • @spender:我不这么认为。当必须重新抛出异常同时保留其原始堆栈时,该类很有用。我已经在其他地方使用它,但在这里对我没有帮助。当抛出异常时,它的调用堆栈根植于工作线程的入口点。那个时候存款人的堆栈早就没有了,所以没有办法在 try..catch 中捕获它。
  • @spender:澄清一下:我倾向于就 SO 和 SE 提出一些困难的问题,因此我经常收到负面反馈。我赞成你的评论只是为了承认你帮助我的积极尝试。所以谢谢! :)

标签: c# multithreading callstack


【解决方案1】:

我知道我可以手动完成,只需记下存放调用堆栈即可

这可能是更清洁的解决方案。

有没有更聪明的方法来欺骗异常自身的调用堆栈,使其看起来好像是连续的?

是的,有一个“聪明”的解决方案 - 和大多数“聪明”的解决方案一样,YMMV。

首先,简要介绍一下术语:what you want isn't a call stack (where the code is returning to); its a causality chain (how the code got here)。

您可以使用AsyncLocal<T> / LogicalCallContext 自己跟踪因果链。一个容易被忽视的问题是the data stored in the logical call context must be immutable。这种方法的一个更严重(谢天谢地更罕见)的问题是,如果您有无限“递归”异步调用,这通常可以正常工作,但如果您在每次调用时增加因果链,您最终将获得无限的内存使用。

设置完成后,您可以使用 Fody / PostSharp / 等自动将因果链跟踪注入您的方法中。

我有一个AsyncDiagnostics library,它使用LogicalCallContext 和PostSharp 自动神奇地确定您的因果链。我先试试看。

【讨论】:

  • 酷!谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-21
  • 1970-01-01
  • 2010-11-17
  • 1970-01-01
  • 1970-01-01
  • 2011-04-19
  • 2018-08-29
相关资源
最近更新 更多