问题描述
我正在尝试通过跟踪定义的某种环境上下文来增强我们的服务器平台。每个上下文至少都有一个ID,随着功能流程的进行,我们的平台各部分可能会或可能不会使用该ID。在上下文中,可以创建线程(或异步调用,或在其他线程上执行的类似WF之类的东西)。我希望这些子线程至少能够参与父级的上下文以获得ContextID。
我想象如下:
using (Context ctx = Context.Create()) {
Log.Print(Context.Current.ID);
Task task = Task.Factory.StartNew( () => {
Log.Print(Context.Current.ID);
using (Context ctx2 = Context.Current.CreateChild()) {
Log.Print(Context.Current.ID);
}
...
}
...
task.Wait();
}
因此,应该打印的内容如下:
\“ ContextID1 \”
\“ ContextID1 \”
\“ ContextID1:ContextID2 \”
与现在相比,帮助跨许多服务器跟踪日志消息的主要目的要容易得多。程序和数据在许多(几百台)机器之间流动,而且太麻烦了,无法从一台机器跟踪到另一台机器。使用环境相关器将极大地帮助您,我现在唯一的问题是我不知道子线程如何自动确定父线程的上下文是什么,更不用说访问它的TLS了。如果我只能得到父主题的ManagedThreadID,则可以使整个事情按我想要的方式工作。
我意识到我可以在创建线程/任务时将Context作为开始参数传递,但是我们平台中有数百万行代码,我不能仅仅进行更改。因此,将其烘焙到核心框架中并使其完全处于环境中将解决该问题,我对此有控制权。
解决方法
我曾经设计过这样的系统,但必须用自定义包装程序替换所有与线程启动相关的代码,这些包装程序可以根据需要概括和抽象出这样的上下文链。不幸的是,我不知道可以解决该问题的透明机制。
您最有可能遇到的问题之一是在线程池上执行代码,并要求它继承父上下文。在这里,您需要考虑到重用线程池线程这一事实。在线程池线程上执行的每项工作都必须妥善处理上下文继承,而不会影响将来将在同一线程上执行的任何无关代码。