У меня есть созданная мной среда ведения журналов, которая может отслеживать «контекст ведения журнала».У него есть подключаемая стратегия, однако чаще всего я использую вариант 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;
}
}
В действительности кажется, что данные ThreadStatic на самом деле делятся между потоками.Это идет вразрез со всем, что я понимаю о потоках.Мне было трудно понять, в чем проблема, пока я не добавил дополнительную запись в журнале, которая отслеживалась, когда каждый поток очищал контекст потока (все потоки выполняются в основном цикле ... в начале, если необходимые сообщенияполучен, контекст инициализирован, а в конце в пункте finally его сброс.) Следующее ведение журнала является ПОСТОЯННЫМ:
[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-a2dd1b1-e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e0e5e5e1e5e5e5e5e1e1e1e1e1e5e0e1e5e1e1e1-d0305-e-5-e-5-db1-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,3b46dcb4ffd6; HandlerName = GroupCreatedNotificationHandler; HandlerId = WORKDEVELOPMENT.1) Найден экземпляр инструмента LTI для guid экземпляра инструмента 0967e031-398f-437d-8949-2a17fe844df0.
[21-12,352: 27] [DEBUG] [TPI.LTI.Facades.TPIFacade: TPI.LTI.Provisioning.Handlers.GroupCreatedNotificationHandler.WORKDEVELOPMENT.1_Thread: 299]: (ContextId = 184e82dd-152b-4bb5-a2c0ede1e5c5e05; 053).e8dd-4fa1-9107-3b46dcb4ffd6; HandlerName = GroupCreatedNotificationHandler; HandlerId = WORKDEVELOPMENT.1) Публикация события в TPI в 'http://tpidev.pearsoncmg.com/tpi/lti/service/event'...
[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: 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? Я пишу код на C # с 2001 года, и никогда раньше не сталкивался с таким поведением. Кажется, в .NET 4 появился новый класс ThreadLocal<T>
, однако я не уверен, что он все равно просто использовал ThreadStatic для внутреннего использования, и поэтому у него возникла бы та же проблема, или он функционировал бы по-другому (и, надеюсь, более надежно). Любое понимание в эту проблему будет очень ценным! Спасибо!