2017-05-25 16 views
0

假设我有一个工作线程,其输入Queue<Task>在连续的while循环内处理。只要外部代码将新的Task存入队列,工作人员就会唤醒并等待任务实例。但是,如果发生异常,我想记录详细信息,包括完整的调用堆栈,以便确定哪个代码路径是错误的。在处理排队任务的工作线程中欺骗调用堆栈

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

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

我知道我可以手动完成,只需通过Environment.StackTrace记下存款呼叫堆栈,并在工作人员中将其与异常一起记录下来。但这仍然是我必须跟踪的两个单独的堆栈。

是否有更巧妙的方式来欺骗异常自己的调用堆栈看起来好像是连续的?因为它有点 - 当任务入队和出队时,点之间只有一点点延迟。

编辑:基本上,我正在寻找一种方式做C#的async确实与调用栈(即合并他们在所发生的所有线程跳),只有我的控制下,一个普通线程内。

+1

Could ['ExceptionDispatchInfo.Throw()'](https://msdn.microsoft.com/en-us/library/system.runtime.exceptionservices.exceptiondispatchinfo(v = vs.110).aspx)是答案? “*引发异常,就好像它从捕获点到调用Throw方法的点一样。*“ – spender

+0

@spender:我不这么认为,当一个异常必须在保留其原始堆栈的同时重新抛出时,这个类很有用,我已经在其他地方使用了它,但是它并没有帮助我。抛出异常,它的调用堆栈根植于工作者线程的入口处,存储器的堆栈早已消失,因此无法在try..catch中捕获它。 – aoven

+0

@spender:只是为了澄清:我倾向于在S​​O和SE上提出一些困难的问题,对此我常常收到负面反馈,我赞成你的评论只是为了承认你积极的尝试来帮助我,所以谢谢你:) – aoven

回答

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,它使用LogicalCallContextPostSharp自动神奇地确定您的因果关系链。我会先尝试一下。

+0

很酷!谢谢! – aoven