jri*_*sta 5 c# multithreading thread-safety threadstatic c#-4.0
我有一个我编写的日志框架,它能够跟踪"日志记录上下文".它有一个可插拔的策略框架,但我最常使用的是ThreadStatic变种,它跟踪[ThreadStatic]变量中的上下文.我一直在尝试解决多线程工作流中的日志记录上下文问题.目标是让所有共享公共线程的方法和类的所有调用的所有日志条目记录相同的上下文信息.因为理论上每个线程都应该获得自己的ThreadStatic变量,所以这个想法似乎很容易.
public class ThreadStaticLoggingContextStrategy: ILoggingContextStrategy
{
public ThreadStaticLoggingContextStrategy()
{
Debug.WriteLine("[INITIALIZE] A new instance of 'ThreadStaticLoggingContextStrategy' has been created.");
}
[ThreadStatic] private LoggingContext _context;
public LoggingContext GetLoggingContext()
{
if (_context == null)
_context = new LoggingContext();
return _context;
}
}
Run Code Online (Sandbox Code Playgroud)
实际上,似乎ThreadStatic数据实际上是跨线程共享的.这违背了我对线程的理解.我很难搞清楚问题是什么,直到我投入额外的日志条目,跟踪每个线程清除线程上下文时(所有线程在主循环上运行...在开始时,如果必要的消息是收到,上下文被初始化,并且在finally子句的最后,它被重置.)以下日志记录是CONSISTENT:
[2011-12-15 16:27:21,233] [DEBUG] [TPI.LTI.Eventing.GroupCreatedNotificationHandler:TPI.LTI.Provisioning.Handlers.GroupCreatedNotificationHandler.WORKDEVELOPMENT.1_Thread:324] :( ContextId = 184e82dd-152b-4bb5- a2c6-3e05b2365c04; TransactionId = 1a11130e-e8dd-4fa1-9107-3b46dcb4ffd6; HandlerName = GroupCreatedNotificationHandler; HandlerId = WORKDEVELOPMENT.1)将工具'0967e031-398f-437d-8949-2a17fe844df0'的事件推送到 http://tpidev.pearsoncmg. com/tpi/lti/service/event ...
[2011-12-15 16:27:21,259] [DEBUG] [TPI.LTI.Facades.LTIFacade:TPI.LTI.Provisioning.Handlers.GroupCreatedNotificationHandler.WORKDEVELOPMENT.1_Thread:299] :( ContextId = 184e82dd-152b-4bb5- a2c6-3e05b2365c04; TransactionId = 1a11130e-e8dd-4fa1-9107-3b46dcb4ffd6; HandlerName = GroupCreatedNotificationHandler; HandlerId = WORKDEVELOPMENT.1)获取工具实例的LTI工具实例guid 0967e031-398f-437d-8949-2a17fe844df0:
[2011-12-15 16:27:21,318] [DEBUG] [TPI.LTI.Facades.LTIFacade:TPI.LTI.Provisioning.Handlers.GroupCreatedNotificationHandler.WORKDEVELOPMENT.1_Thread:299] :( ContextId = 184e82dd-152b-4bb5- a2c6-3e05b2365c04; TransactionId = 1a11130e-e8dd-4fa1-9107-3b46dcb4ffd6; HandlerName = GroupCreatedNotificationHandler; HandlerId = WORKDEVELOPMENT.1)找到工具实例guid 0967e031-398f-437d-8949-2a17fe844df0的LTI工具实例.
[2011-12-15 16:27:21,352] [DEBUG] [TPI.LTI.Facades.TPIFacade:TPI.LTI.Provisioning.Handlers.GroupCreatedNotificationHandler.WORKDEVELOPMENT.1_Thread:299] :( ContextId = 184e82dd-152b-4bb5- a2c6-3e05b2365c04; TransactionId = 1a11130e-e8dd-4fa1-9107-3b46dcb4ffd6; HandlerName = GroupCreatedNotificationHandler; HandlerId = WORKDEVELOPMENT.1)在'http://tpidev.pearsoncmg.com/tpi/lti/service/event'向TPI发布事件...
[2011-12-15 16:27:21,428] [DEBUG] [TPI.LTI.Eventing.GroupCreatedNotificationHandler:TPI.LTI.Provisioning.Handlers.GroupCreatedNotificationHandler.WORKDEVELOPMENT.2_Thread:301]: [LOG]重置日志记录上下文!!
[2011-12-15 16:27:21,442] [DEBUG] [TPI.LTI.Eventing.GroupCreatedNotificationHandler:TPI.LTI.Provisioning.Handlers.GroupCreatedNotificationHandler.WORKDEVELOPMENT.2_Thread:299]:队列中没有待处理的消息.GroupCreatedNotificationHandler.WORKDEVELOPMENT.2处理程序正在等待......
[2011-12-15 16:27:22,282] [DEBUG] [TPI.LTI.Facades.TPIFacade:TPI.LTI.Provisioning.Handlers.GroupCreatedNotificationHandler.WORKDEVELOPMENT.1_Thread:301]:事件发布到TPI.
[2011-12-15 16:27:22,283] [DEBUG] [TPI.LTI.Eventing.GroupCreatedNotificationHandler:TPI.LTI.Provisioning.Handlers.GroupCreatedNotificationHandler.WORKDEVELOPMENT.1_Thread:301]:收到来自提供商的回复:
您可以看到在这种特殊情况下有两个线程,1_Thread和2_Thread.我用斜体显示了应该包含在1_Thread的每个日志条目开头的上下文数据.我已经在2_Thread中加粗了重置日志记录上下文的点.在那之后,缺少1_Thread的所有上下文信息.到目前为止,在几十个测试中,在另一个上重置日志记录上下文后,所有线程的上下文信息都会丢失.
我误解了ThreadStatic吗?我从2001年开始编写C#代码,之前我从未经历过这种行为.似乎ThreadLocal<T>.NET 4中有一个新类,但是我不确定它是否只是内部使用了ThreadStatic,因此会出现同样的问题,或者它的功能是否有所不同(希望更可靠).对这个问题有任何见解会非常感激!谢谢!