c#锁定泛型函数

时间:2011-12-07 07:34:02

标签: c# multithreading generics locking

我有这样一个班级:

public static class CacheManager
{
    static object lockObject = new object();

    static MemcachedClient CacheObject
    {
        get
        {
            if (!MemcachedClient.Exists(Settings.Default
                .CacheInstanceName))
            {
                MemcachedClient.Setup(Settings.Default
                    .CacheInstanceName,
                        new string[] {Settings.Default
                            .CacheHostAddress});
            }
            //
            //
            return MemcachedClient.GetInstance(Settings
                .Default.CacheInstanceName);
        }
    }

    public static List<TData> Get<TData>(string key, Func<List<int>> getListCallback,
        Func<int, TData> getItemCallback) where TData : class
    {
        var result = new List<TData>();
        //
        //
        var list = CacheObject.Get(key);
        if (list == null)
        {
            lock (lockObject)
            {
                list = CacheObject.Get(key);
                if (list == null)
                {
                    list = getListCallback();
                    CacheObject.Set(key, list);
                    //
                    //
                    foreach (var id in (List<int>)list)
                    {
                        var item = getItemCallback(id);
                        result.Add(item);
                        CacheObject.Set(string.Concat(key, id), item);
                    }
                }
            }
        }
        else
        {
            foreach (var id in (List<int>)list)
            {
                var itemKey = string.Concat(key, id);
                //
                //
                var item = CacheObject.Get(itemKey);
                if (item == null)
                {
                    lock (lockObject)
                    {
                        item = CacheObject.Get(itemKey);
                        if (item == null)
                        {
                            item = getItemCallback(id);
                            CacheObject.Set(itemKey, item);
                        }
                    }
                }
                //
                //
                result.Add((TData)item);
            }
        }
        //
        //
        return (List<TData>)result;
    }

    public static void Remove(string key)
    {
        CacheObject.Delete(key);
    }
}

它在类库中使用:

public class NewsRepository : BaseRepository, IRepository
{

    public List<News> FindAll()
    {
        return CacheManager.Get<News>(key,
            () => clientEntities.News.OrderByDescending(n => n.DateCreated).Select(n => n.NewsId).ToList(),
            (id) => clientEntities.News.Single(n => n.NewsId == id));
    }
}
public class PagesRepository : BaseRepository
{
    public List<Page> FindAll()
    {

        return CacheManager.Get<Page>(key,
            () => clientEntities.Pages.OrderBy(p => p.PageId).Select(p => p.PageId).ToList(),
            (id) => clientEntities.Pages.Single(p => p.PageId == id));
    }
}

我的问题是:例如,NewsRepository没有在缓存中找到新闻并获得锁定并开始加载数据,但此时PagesRepository没有在缓存中找到页面。 PagesRepository的CacheManager会被NewsRepository锁定还是(我认为是这样)NewsRepository的CacheManager是另一个静态类,它的内部锁不会触及PagesRepository的CacheManager?

2 个答案:

答案 0 :(得分:13)

非泛型类型的静态字段(本身不嵌套在泛型类型中等)只存在一次,因此所有锁都会发生冲突。

如果(注释)你的目标是使每个类型的锁(来自通用方法),那么最好的方法是:

public static class CacheManager {
    static class TypeLock<T> {
        public static readonly object SyncLock = new object();
    }
    ...
    void SomeGenericMethod<TData>(args) {
       ...
       lock(TypeLock<TData>.SyncLock) {
          ...
       }
       ...
    }
}

此处,SyncLockT只存在一次(且仅一次),因此每TData。这样您就可以保留现有的API(CacheManager不是通用的)。

答案 1 :(得分:5)

两者都将对lockObject使用相同的引用,因此使用相同的锁。