編集を開始
これを行う「正しい」方法(4.5より前)は、ここで概説されているように、SynchronizationContextを使用することです:http://msdn.microsoft.com/en-us/magazine/gg598924.aspx
4.5ではSynchronizationContextはasync/awaitキーワードで自動的に処理されると思いますが、確認するのに十分な作業を行っていません。
4.0では、「TaskScheduler.FromCurrentSynchronizationContext」を使用して、現在のスレッドのコンテキストをキャプチャすることができます(私の場合、これにはHttpContextが含まれますが、BCLのさまざまな部分で同様の構造が提供されます)。
編集終了
主な質問は次のとおりです。
次は、タスクと「コンテキスト」を共有するための「安全な」メカニズムですか?
あまり詳しく説明しないと、私のユースケースでは、コンテキストをアクションに直接プッシュすることはできません。
public static class ContextCaller{
[ThreadStatic]
public static object SharedState;
public static Task InvokeWithContext(this Action theAction){
//We're still running in the "outer" context,
//so we can collect a variable and store it in the thread-static
//field by closing it into the task.
var context = new object();
var t = new Task(()=>{
try{
//close in the context
SharedState = context;
theAction();
}
finally{
//teardown the shared state.
SharedState = null;
}
});
t.Start();
return t;
}
}
そして今、クライアントコード:
//client code:
Action doWork = ()=>{
var state = ContextCaller.SharedState;
//do work on state, potentially throwing an exception in the process.
};
//cause the task to be invoked with some data available only on this thread.
doWork.InvokeWithContext();
タスクとスレッドの関係についての私の理解に基づくと、上記は安全であるはずです。理由は次のとおりです。
- 1つのタスクは正確に1つのスレッドで実行されます(アクションが追加のタスク/スレッドを生成しないことを前提としています)。
- ThreadStaticフィールドは、「theAction()」の実行前に設定され、「finally」は、結果に関係なく、「theAction()」の呼び出し後にこのフィールドがリセットされることを保証します。
「theAction」へのパラメーターを明示的に閉じる以外に、タスクのコンテキストを定義するための他のより良いパターンはありますか?