• Авторизация


Потокобезопасное кэширование 28-12-2007 20:17 к комментариям - к полной версии - понравилось!


Иногда возникает необходимость кэшировать результат выполнения какой-либо функции между несколькими потоками. Конструкция lock не является оптимальной, гораздо правильнее использовать класс ReaderWriterLock. Ниже представлен generic-класс для реализации подобного хэширования.

using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
 
/// <summary>
/// Потокобезопасный кэш
/// </summary>
/// <typeparam name="TKey">Тип ключа</typeparam>
/// <typeparam name="TValue">Тип значения</typeparam>
public sealed class Cache<TKey, TValue>
{
    /// <summary>
    /// Делегат для получения значения
    /// </summary>
    /// <param name="keyVal">ключ</param>
    /// <returns>значение</returns>
    public delegate TValue HowToObtainValue(TKey keyVal);
 
    /// <summary>
    /// Получение значения из кэша
    /// </summary>
    /// <param name="key">ключ</param>
    /// <returns></returns>
    public TValue Get(TKey key)
    {
        return Get(key, obtainer);
    }
 
    /// <summary>
    /// Получение значения из кэша
    /// </summary>
    /// <param name="key">ключ</param>
    /// <param name="howToObtainValue">делегат, используемый в случае 
    /// отсутсвия значения к кэше</param>
    /// <returns></returns>
    public TValue Get(TKey key, HowToObtainValue howToObtainValue)
    {
        rwl.AcquireReaderLock(Timeout.Infinite);
        try
        {
            TValue theValue;
            if(!dic.TryGetValue(key, out theValue))
            {
                LockCookie lc = rwl.UpgradeToWriterLock(Timeout.Infinite);
                try
                {
                    theValue = howToObtainValue(key);
                    dic.Add(key, theValue);
                }
                finally
                {
                    rwl.DowngradeFromWriterLock(ref lc);
                }
            }
            return theValue;
        }
        finally
        {
            rwl.ReleaseReaderLock();
        }
    }
 
    /// <summary>
    /// Констркутор
    /// </summary>
    /// <param name="underlyingDictionaryImplementation">реализация IDictionary</param>
    /// <param name="func">получение параметра</param>
    public Cache(    IDictionary<TKey,TValue> underlyingDictionaryImplementation, 
                    HowToObtainValue func)
    {
        dic = underlyingDictionaryImplementation;
        obtainer = func;
        rwl = new ReaderWriterLock();
    }
 
    public Cache(HowToObtainValue func)
        : this(new Dictionary<TKey, TValue>(), func)
    { }
 
    /// <summary>
    /// Конструктор по умолчанию
    /// </summary>
    public Cache():this(null)
    {}
 
 
    private ReaderWriterLock rwl;
    private IDictionary<TKey, TValue> dic;
    private HowToObtainValue obtainer;
 
    #if DEBUG
    /// <summary>
    /// !!! Пример использования !!!
    /// </summary>
    public static void Sample()
    {
        Cache<int, int> cache1 = new Cache<int, int>(
            delegate(int keyVal)
                {
                    Trace.WriteLine("Вычисляем для " + keyVal);
                    return keyVal*keyVal;
                }
            );
        for (int i = 1; i < 100; ++i)
        {
            Trace.WriteLine(cache1.Get(i));
        }
        for (int i = 1; i < 100; ++i)
        {
            Trace.WriteLine(cache1.Get(i));
        }
    }
    #endif
}
вверх^ к полной версии понравилось! в evernote


Вы сейчас не можете прокомментировать это сообщение.

Дневник Потокобезопасное кэширование | dimzon541 - Поток не замутненного разумом сознания... | Лента друзей dimzon541 / Полная версия Добавить в друзья Страницы: раньше»