我正在编写一个应用程序,我需要记录现有代码。代码在并行环境中运行。出于记录目的,我需要找到彼此不同的调用栈,例如:
public class ThreadedLogicClass
{
public void MethodOneThreaded()
{
StackTrace trace = new StackTrace();
StackFrame frame = trace.GetFrame(1);
MethodBase methodBase = frame.GetMethod();
Thread thread = new Thread(new ThreadStart(this.ThreadedLogic));
thread.Start();
}
public void MethodOneNonThreaded()
{
StackTrace trace = new StackTrace();
StackFrame frame = trace.GetFrame(1);
MethodBase methodBase = frame.GetMethod();
this.NonThreadedLogic();
}
private void ThreadedLogic()
{
StackTrace trace = new StackTrace();
StackFrame frame = trace.GetFrame(1);
MethodBase methodBase = frame.GetMethod();
Thread thread = new Thread(new ThreadStart(this.LastCall));
thread.Start();
}
private void NonThreadedLogic()
{
StackTrace trace = new StackTrace();
StackFrame frame = trace.GetFrame(1);
MethodBase methodBase = frame.GetMethod();
this.LastCall();
}
private void LastCall()
{
StackTrace trace = new StackTrace();
StackFrame frame = trace.GetFrame(1);
MethodBase methodBase = frame.GetMethod();
}
}
考虑这个主要计划:
ThreadedLogicClass obj = new ThreadedLogicClass();
Console.WriteLine();
Console.WriteLine(" =======> Calling MethodOneThreaded");
obj.MethodOneThreaded();
Console.WriteLine(" =======> End Calling MethodOneThreaded");
Console.WriteLine();
Console.WriteLine(" =======> Calling MethodOneNonThreaded");
obj.MethodOneNonThreaded();
Console.WriteLine(" =======> End Calling MethodOneNonThreaded");
从这里我需要识别两个独特的调用堆栈及其各种端点。
1。)MethodOneThreaded - > ThreadedLogic - >最后一次通话 2.)MethodOneNonThreaded - > NonThreadedLogic - >最后呼叫
我想要的是调用方法调用可能像主方法中的开始/结束调用一样,用于记录上下文以及可能与上下文中的对象关联的一些数据。
有人可以引导我到一条路线,在那里我可以找到有关如何识别这两者的更多信息。
识别的原因是创建单独的上下文来存储数据,直到调用堆栈结束,我需要维护该数据以便以后用于日志服务。
任何帮助都将受到高度赞赏。
答案 0 :(得分:2)
您可以使用StackFrame
和StackTrace
诊断类:
var frames = new StackTrace().GetFrames();
这将为您提供有关整个调用堆栈的信息,包括IL和本机代码偏移。如果您还需要代码行号,则需要提供调试信息(pdb
s)。
请注意,优化可以使这一点相当令人惊讶,因为它将彻底摆脱许多方法调用。如果您有使用WinDbg和类似工具的经验,只要保留原始版本中的pdb
,就可以轻松获取偏移中的行号。
<强>更新强>
哦,你想在线程启动时识别调用堆栈 ?我很害怕你运气不好。除了在Thread.Start
调用周围创建公共包装类之外,没有简单的方法可以处理在线程内传递所需信息。 .NET(也不是Windows)不会跟踪谁开始了哪个线程以及在哪里开始。
这仍然可以做到看起来有点优雅。如果我们假设代码中没有await
s,您可以执行以下操作:
void Main()
{
ThreadHelper.Start(() => Console.WriteLine(ThreadContext.CallerTrace.ToString()));
}
public static class ThreadHelper
{
public static void Start(Action action)
{
var capturedStack = new StackTrace(1);
new Thread(() => { ThreadContext.CallerTrace = capturedStack; action(); })
.Start();
}
}
public static class ThreadContext
{
[ThreadStatic]
public static StackTrace CallerTrace;
}
使用ThreadHelper.Start
代替new Thread(...).Start()
,您可以确保在启动新线程之前捕获堆栈信息,然后传入内部。 ThreadStatic
静态字段可以从任何地方访问,而不同的线程可以访问。您当然希望加入实际调用堆栈与ThreadContext.CallerTrace
中捕获的调用堆栈(如果首先存在)。
扩展这个以“开始......结束”的方式工作应该是非常微不足道的。您可以使用“假”一次性用品,并执行以下操作:
using (MethodCallLogger.Log(MethodInfo.GetCurrentMethod()))
{
// Do your stuff
}
MethodCallLogger.Log
的返回值可以是在构造函数中写入“begin”的简单类,而在dispose方法中写入“end”。它当然可以访问完整的堆栈跟踪,包括ThreadContext.CallerTrace
中捕获的跟踪。
如果你想要包装方法调用,你可以创建一个简单的帮助器方法:
public static class MethodCallHelper
{
public static void Log(Action action)
{
try
{
Console.WriteLine("Begin " + action.Method.ToString());
action();
}
finally
{
Console.WriteLine("End " + action.Method.ToString());
}
}
}