更新:このメソッドがスレッド セーフでない場合は許容されますが、スレッド セーフにする方法を知りたいと思っています。key
また、回避できる場合は、すべての値に対して単一のオブジェクトをロックしたくありません。
元の質問:キーと関数を受け取り、指定されたキーでオブジェクトがキャッシュされているかどうかをチェックする高階関数を書きたいとします。が含まれている場合、キャッシュされた値が返されます。それ以外の場合は、指定された関数が実行され、結果がキャッシュされて返されます。
これが私のコードの簡略版です:
public static T CheckCache<T>(string key, Func<T> fn, DateTime expires)
{
object cache = HttpContext.Current.Cache.Get(key);
//clearly not thread safe, two threads could both evaluate the below condition as true
//what can I lock on since the value of "key" may not be known at compile time?
if (cache == null)
{
T result = fn();
HttpContext.Current.Cache.Insert(key, result, null, expires, Cache.NoSlidingExpiration);
return result;
}
else
return (T)cache;
}
key
また、コンパイル時に可能なすべての値を知っているわけではないとします。
このスレッドを安全にするにはどうすればよいですか? 1 つ以上のスレッドが私の条件を true と評価するのを防ぐために、ここでロックを導入する必要があることはわかっていますが、何をロックすればよいかわかりません。ロックについて読んだ例の多く ( Jon Skeet の記事など) では、ロック専用の「ダミー」プライベート変数を使用することを推奨しています。この場合、コンパイル時にキーが不明であるため、これは不可能です。すべての に同じロックを使用することで、このスレッドを簡単に安全にできることはわかっていますkey
が、それは無駄になる可能性があります。
さて、私の主な質問は次のとおりです。
ロックオンは可能key
ですか?ここで文字列インターンが役立ちますか?
.NET 2.0 string interning inside outを読んだ後、明示的に呼び出しString.Intern()
て、文字列の値から文字列のインスタンスへの 1 対 1 のマッピングを取得 できることを理解しました。これはロックオンに適していますか?上記のコードを次のように変更しましょう。
public static T CheckCache<T>(string key, Func<T> fn, DateTime expires)
{
//check for the scenario where two strings with the same value are stored at different memory locations
key = String.Intern(key);
lock (key) //is this object suitable for locking?
{
object cache = HttpContext.Current.Cache.Get(key);
if (cache == null)
{
T result = fn();
HttpContext.Current.Cache.Insert(key, result, null, expires, Cache.NoSlidingExpiration);
return result;
}
else
return (T)cache;
}
}
上記の実装はスレッドセーフですか?