2011-12-15 14 views
4

私は "ロギングコンテキスト"を追跡する能力を持っている私が書いたロギングフレームワークを持っています。それはプラグイン可能な戦略フレームワークを持っていますが、最も頻繁に使用するのは、[ThreadStatic]変数でコンテキストを追跡する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データは実際にスレッド間で共有されているようです。これはスレッディングについて理解しているすべてのものに反します。私は、各スレッドがスレッドコンテキストをクリアした(すべてのスレッドがメインループで実行された時を追跡する)余分なログエントリを投げ込むまで、問題の内容を把握するのに苦労していました。コンテキストが初期化され、受信し、そして最後に句の終わりに、そのリセット)は、以下のロギングが一致している:。

[2011-12-15 16:27:21233] [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; http://tpidev.pearsoncmg.com/tpi/lti/service/eventに工具 '0967e031-398f-437d-8949-2a17fe844df0' のイベントをプッシュ HandlerId = WORKDEVELOPMENT.1) ...

[2011-12-15 16:27:21259] [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ツールインスタンスの取得 instanc電子GUID 0967e031-398f-437d-8949-2a17fe844df0:

[2011-12-15 16:27:21318] [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:21352] [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)出版イベント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]: [ログ]ログの再設定コンテキスト!

[2011-12-15 16:27:21442] [DEBUG] [TPI.LTI.Eventing.GroupCreatedNotificationHandler: TPI.LTI.Provisioning.Handlers.GroupCreatedNotificationHandler.WORKDEVELOPMENT.2_Thread: 299]:いいえキューに保留中のメッセージ。 GroupCreatedNotificationHandler.WORKDEVELOPMENT.2ハンドラは...待って ある

[2011-12-15 16:27:22282] [DEBUG] [TPI.LTI.Facades.TPIFacade: TPI.LTI.Provisioning.Handlers。 GroupCreatedNotificationHandler.WORKDEVELOPMENT.1_Thread: 301]:イベントがTPIに公開されました。

[2011-12-15 16:27:22283] [DEBUG] [TPI.LTI.Eventing.GroupCreatedNotificationHandler: TPI.LTI.Provisioning.Handlers.GroupCreatedNotificationHandler.WORKDEVELOPMENT.1_Thread: 301]:受信プロバイダからの応答:

この特定のケースでは、1_Threadと2_Threadの2つのスレッドがあります。私は1_Threadのすべてのログエントリの冒頭にインクルードされるはずのコンテキストデータをイタリック体にしました。私は2_Threadのポイントを太字にして、ロギングコンテキストをリセットしました。その時点以降、1_Threadのコンテキスト情報はすべて失われています。今までの数十回のテストでは、ロギングコンテキストが別のスレッドにリセットされた後、すべてのスレッドのコンテキスト情報が失われていました。

私はThreadStaticを誤解していますか?私は2001年からC#コードを書いていますが、以前はこのような現象は経験していませんでした。 .NETの新しいThreadLocal<T>クラスがあるようですが、とにかくThreadStaticを内部的に使用しているのかどうかは分かりませんし、同じ問題があるのか​​、それとも機能が異なるのでしょうか。問題は大いに賞賛されるでしょう!ありがとう!

+0

ThreadStaticフィールドを使用しているコードを投稿してください。 –

+0

私は実際にしました。そのかなりストレートフォワード。戦略はシングルトンであり、アプリケーション全体に1つしか存在しません。 – jrista

答えて

14

このフィールドはであるため、固定ではありません。静的フィールドにのみ適用されます。

これが4.0である場合@MarcGravellが問題の原因である、あなたのフィールドは静的ではありません指摘しているように、多分ThreadLocal<T>

+0

OMG。ありがとう!私はちょうど時間をかけて、ThreadStaticについて知ることのできるすべてを読んでいました。私は数十回それを読んでいるに違いない、それは静的だったSWORNを持つことができただけで、私はそれを見ていなかった。 – jrista

+0

+1私はちょうど同じ問題を抱えていました...そして同じ解決策:do'h –

0

を見てください。

ただし、消費者がGetLoggingContextからの返品を保存する場合、この値はスレッド間で共有できるようになります。私は一般的に、クラスの実装の詳細として何かThreadStatic変数を使用しようとします。

+0

確かに、私は知っていますGetLoggingContext呼び出しは常にコンテキストを取得するために使用され、ロギングフレームワーク内で呼び出されます。このコードは、実際にロギングを行うコードから数度離れており、深く埋め込まれた実装の詳細です。私は、ローカルにそのコピーをキャッシュする人は誰も心配していません。この特定の戦略を、他のプログラマーが実際に使用するILoggerインターフェースにまで絞られたロギング・フレームワークの実装の詳細と考えることができます。私は一般的に同じルールに従います...内部の詳細としてThreadStaticを保つ。 – jrista

関連する問題