2014 年 11 月 18 日更新 - 在浏览 log4net 源存储库时,我发现 LogicalThreadContext 的实现在 2011 年 11 月被修改为它使用 CallContext.LogicalSetData 存储其属性(并使用 LogicalGetData 获取它们)。这很重要,因为这意味着 LogicalThreadContext 现在应该可以正常工作。存储在 LogicalThreadContext 中的任何数据都应该“流向”任何子线程或任务。这与 ThreadContext(以及 LogicalThreadContext 的旧实现)相比,其中存储在上下文中的数据将保持在当前线程的本地,并且不会流向子线程/任务。
如果你有兴趣,这里是变化:
希望遇到这个老问题的人会发现这些信息很有用。
log4net 提供了两个不同的“线程上下文”对象: ThreadContext和LogicalThreadContext,每个对象都有一个属性包,Properties。ThreadContext 有一个ThreadContextProperties包,而 LogicalThreadContext 有一个LogicalThreadContextProperties包。
ThreadContext 可能更常被称为“MDC”。LogicalContext 可能更常被称为“LDC”。我将在这篇文章的其余部分使用简称。
MDC.Properties 使用System.Threading.Thread.SetData实现,而 LDC.Properties 使用System.Runtime.Remoting.Messaging.CallContext.SetData实现。
为了比较,NLog 只公开“MDC”(现在称为 MappedDiagnosticContext)来存储线程本地属性。NLog的实现使用System.Threading.Thread.SetData,所以它的实现和log4net的一样。
在 log4net 和 NLog 中,“MDC”属性都存储在字典中,而字典本身存储在线程本地存储中。
在这种情况下,将字典存储在用 [ThreadStatic] 修饰的类成员变量中是否等效?
[ThreadStatic]
private static IDictionary<string, string> threadProperties;
使用 .NET 4.0 的新 ThreadLocal 类的等效(或类似)声明是什么?
最终,LDC 和 MDC 之间真正的、实际的区别是什么?即使在阅读了上面链接的 MSDN 主题之后,我也不清楚。你什么时候真的会使用其中一个?似乎我在 log4net 和上下文中看到的绝大多数参考/示例都是针对 GDC(全局 - 我理解)、NDC(嵌套 - 我也理解)和 MDC。我在谷歌搜索时可以找到的大多数 LDC(或 LogicalThreadContext)参考资料都与签入 log4net 源代码存储库有关,而不是实际使用。LDC 几乎从不提出问题或示例。
我确实发现这个链接提供了一些关于与 log4net 开发人员之一 Nicko Cadell 的区别的非常好的信息,但我仍然不清楚。
与 log4net 没有直接关系的一个更大的问题是 Thread.SetData 和 CallContext.SetData 之间的实际区别是什么?
根据CallContext MSDN 文章,CallContext 数据可以传播到另一个 AppDomain。要传播,存储在 CallContext 中的数据项必须公开ILogicalThreadAffinative接口。所以,这似乎是 Thread.SetData 和 CallContext 之间的区别之一。
根据 Nicko Cadell 链接,log4net 没有实现 ILogicalThreadAffinative,因此不会传播 LDC 属性。
也许这里有足够的东西我应该能够回答我自己的问题,也许不是。我仍在努力理解。
如果你使用 log4net,你每个人都使用 MDC、LDC 吗?如果你使用 MDC,是不是因为大多数“现实世界”的例子似乎都在使用它?如果您使用 LDC,您有使用它的具体原因吗?如果你同时使用,你如何选择何时使用哪个?
请注意,我看过一些关于 MDC(可能是 LDC)的文章,由于线程切换,可能无法在 ASP.net 应用程序中正常工作。我对这个问题不是特别感兴趣,因为我不在 ASP.net 中工作。
实际上,我在这里找到了一些关于 SO 的有用帖子,它们可能有助于讨论:
提前致谢!