今回は、System.Runtime.Remoting.Messasing.CallContextクラスのLogicalSetData/LogicalGetDataメソッドについて
ちょこっとメモメモ。
すべてのスレッドには、実行コンテキスト (Execution Context) が関連付けられています。
実行コンテキストには
- そのスレッドのセキュリティ設定 (圧縮スタック、Thread.Principal, Windowsの認証情報)
- ホスト設定 (HostExecutionContextManager)
- 論理呼び出しコンテキストデータ (CallContext)
が紐付いています。
その中でも、論理呼び出しコンテキスト (CallContext) は、LogicalSetDataメソッド、LogicalGetDataメソッドを
利用することにより、同じ実行コンテキストを持つスレッド間でデータを共有することができます。
既定では、CLRは起動元のスレッドの実行コンテキストが自動的に伝播されるようにしてくれます。
実行コンテキストの伝播方法は、ExecutionContextクラスを利用することにより変更することができます。
ExecutionContext.SuppressFlowメソッドにはSerucityCriticalAttributeが付与されているので
環境によっては動作しなくなる可能性があることに注意が必要です。特にクライアントアプリでは。
(SerucityCriticalAttributeは、完全信頼を要求する属性)
LogicalSetDataおよびLogicalGetDataメソッドの利用方法はDictionaryと同じ要領です。
以下サンプルです。
#region CallContextSamples-01 /// <summary> /// 実行コンテキスト(ExecutionContext)と論理呼び出しコンテキスト(CallContext)のサンプルです。 /// </summary> public class CallContextSamples01 : IExecutable { public void Execute() { // // すべてのスレッドには、実行コンテキスト (Execution Context) が関連付けられている。 // 実行コンテキストには // ・そのスレッドのセキュリティ設定 (圧縮スタック、Thread.Principal, Windowsの認証情報) // ・ホスト設定 (HostExecutionContextManager) // ・論理呼び出しコンテキストデータ (CallContext) // が紐付いている。 // // その中でも、論理呼び出しコンテキスト (CallContext) は、LogicalSetDataメソッド、LogicalGetDataメソッドを // 利用することにより、同じ実行コンテキストを持つスレッド間でデータを共有することができる。 // 既定では、CLRは起動元のスレッドの実行コンテキストが自動的に伝播されるようにしてくれる。 // // 実行コンテキストの伝播方法は、ExecutionContextクラスを利用することにより変更することができる。 // ExecutionContext.SuppressFlowメソッドにはSerucityCriticalAttribute // が付与されているので、環境によっては動作しなくなる可能性がある。 // (SerucityCriticalAttributeは、完全信頼を要求する属性) // var numberOfThreads = 5; using (var cde = new CountdownEvent(numberOfThreads)) { // // メインスレッド上にて、論理呼び出しコンテキストデータを設定. // CallContext.LogicalSetData("Message", "Hello World"); // // 既定の設定のまま (親元のExecutionContextをそのまま継承) で、別スレッド生成. // ThreadPool.QueueUserWorkItem(ShowCallContextLogicalData, new ThreadData("First Thread", cde)); // // 実行コンテキストの伝播方法を変更. // SuppressFlowメソッドは、実行コンテキストフローを抑制するメソッド. // SuppressFlowメソッドは、AsyncFlowControlを戻り値として返却する。 // 抑制した実行コンテキストを復元するには、AsyncFlowControl.Undoを呼び出す。 // AsyncFlowControl flowControl = ExecutionContext.SuppressFlow(); // // 抑制された実行コンテストの状態で、別スレッド生成. // ThreadPool.QueueUserWorkItem(ShowCallContextLogicalData, new ThreadData("Second Thread", cde)); // // 実行コンテキストを復元. // flowControl.Undo(); // // 再度、別スレッド生成. // ThreadPool.QueueUserWorkItem(ShowCallContextLogicalData, new ThreadData("Third Thread", cde)); // // 再度、実行コンテキストを抑制し、抑制されている間に論理呼び出しコンテキストデータを変更し // その後、実行コンテキストを復元する. // flowControl = ExecutionContext.SuppressFlow(); CallContext.LogicalSetData("Message", "Modified...."); ThreadPool.QueueUserWorkItem(ShowCallContextLogicalData, new ThreadData("Fourth Thread", cde)); flowControl.Undo(); ThreadPool.QueueUserWorkItem(ShowCallContextLogicalData, new ThreadData("Fifth Thread", cde)); cde.Wait(); } } void ShowCallContextLogicalData(object state) { var data = state as ThreadData; Console.WriteLine( "Thread: {0, -15}, Id: {1}, Message: {2}" ,data.Name ,Thread.CurrentThread.ManagedThreadId ,CallContext.LogicalGetData("Message") ); data.Counter.Signal(); } #region Inner Classes class ThreadData { public string Name { get; private set;} public CountdownEvent Counter { get; private set;} public ThreadData(string name, CountdownEvent cde) { Name = name; Counter = cde; } } #endregion } #endregion
以下、実行結果の例です。
Thread: Second Thread , Id: 4, Message: Thread: First Thread , Id: 3, Message: Hello World Thread: Fourth Thread , Id: 3, Message: Thread: Fifth Thread , Id: 3, Message: Modified.... Thread: Third Thread , Id: 4, Message: Hello World
別スレッドで処理を行うようにしているので、実行結果もバラバラに
表示される可能性があります。上記の結果を呼び出し順に並べ替えると
以下のようになります。
Thread: First Thread , Id: 3, Message: Hello World Thread: Second Thread , Id: 4, Message: Thread: Third Thread , Id: 4, Message: Hello World Thread: Fourth Thread , Id: 3, Message: Thread: Fifth Thread , Id: 3, Message: Modified....
実行コンテキストを抑制 (SuppressFlow)している間、LogicalGetDataメソッドから
値が取得できていないことがわかります。
尚、サンプルでは各スレッドの待ち合わせにカウントダウンラッチを利用しています。
CountdownEventクラスについては、以下の記事をご参照ください。
- .NET クラスライブラリ探訪-043 (System.Threading.CountdownEvent(1))(カウントダウンラッチ, CancelaltionToken, .NET 4.0)
- .NET クラスライブラリ探訪-044 (System.Threading.CountdownEvent(2))(N個の処理を待機, .NET 4.0)
- .NET クラスライブラリ探訪-045 (System.Threading.CountdownEvent(3))(キャンセルトークンの利用, CancellationToken, Wait, .NET 4.0)
- .NET クラスライブラリ探訪-046 (System.Threading.CountdownEvent(4))(AddCount, Reset, .NET 4.0)
以下、参考資料です。
- ExecutionContext.SuppressFlow メソッド
- AsyncFlowControl 構造体
- CallContext クラス
================================
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場