Обновление: Допустимо, если этот метод не является потокобезопасным, но мне интересно узнать, как сделать его потокобезопасным. Кроме того, я не хочу блокировать один объект для всех значений 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+ нить не оценивала мои условия как истинные, но я не знаю, что блокировать. Многие из примеров, которые я прочитал о блокировке (например, статья Джона Скита), рекомендуем использовать закрытую переменную "dummy", которая используется только для блокировки. В этом случае это невозможно, потому что ключи неизвестны во время компиляции. Я знаю, что я мог бы тривиально сделать этот поток безопасным, используя один и тот же замок для каждого key
, но это может быть расточительным.
Теперь, мой главный вопрос:
Можно ли заблокировать key
? Будет ли поддержка интернирования здесь?
После прочтения .NET 2.0 строка интернирования внутри 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;
}
}
Является ли указанный выше поток реализации безопасным?