1

我有一个帮助类,它读取一个大的 XML 文档并生成一个 c# 对象列表。

我经常使用这些对象,所以我认为最好的方法是将它们保存在内存中,然后从那里访问它们。

我做了一个简单的存储库,它从内存中获取一个对象,如果不存在,它会添加它。

存储库如下所示:

public class XmlDocumentRepository
{
    private readonly ICacheStorage _cacheStorage;
    public XmlDocumentRepository(ICacheStorage cacheStorage)
    {
        _cacheStorage = cacheStorage;
    }

    private readonly object _locker = new object();

    private void DeserializeXmlDocument()
    {
        lock (_locker)
        {
            // I deserialize the xml document, i generate the c# classes, and save them in cache
            IEnumerable<Page> pages = new XmlDeserializerHelper().DeserializeXml();    

            foreach(var page in pages)
            {
                _cacheStorage.Add(page_Id, page);
            }
        }
    }

    public Page GetPage(Guid page_Id)
    {
        Page page = _cacheStorage.Get<Page>(page_Id);
        if (page != null)
            return page;

        lock (_locker)
        {
            page = _cacheStorage.Get<Page>(page_Id);
            if (page != null)
                return page;

            DeserializeXmlDocument();

            page = _cacheStorage.Get<Page>(page_Id);
            return page;
        }
    }
}

用于 Web 应用程序(更准确地说是XmlDocumentRepositoryasp.net mvc)。

存储库的实现是否良好?我lock是否正确使用了这些语句?

4

2 回答 2

1

在我对这个问题的评论中,我误解了共享的缓存。我认为您将需要执行以下选项之一:

  • 制作XmlDocumentRepository一个用于所有请求的单例,因为锁定对象是一个私有字段,因此每个请求都会有一个带有新字段的存储库的新实例。
  • 使锁对象成为静态字段,以便在所有XmlDocumentRepository实例之间共享。
于 2013-03-06T13:02:08.907 回答
0

作为主要规则,您希望保护对多个线程使用的数据存储的所有访问变化。我看到您的实施存在几个潜在问题;

1:ICacheStorage 是从外部提供的,这意味着这个集合可以在别处被修改,它可能被锁保护也可能不被锁保护。也许您应该要求集合本身在内部使用锁定或其他类型的线程安全机制?

2:您对数据访问的锁定保护不一致。在 GetPage 中,您在应用锁之前访问 _cacheStorage,而在反序列化中,您在锁中访问它。这意味着您可能会得到一个结果,其中一个正在添加到缓存中,而另一个正在从中获取。

3:您是否需要缓存、xml 读取或两者都需要线程安全?如果只需要保护缓存,则将 xml 的读取移到锁之外。如果同时保护两者,则应将整个 GetPage 函数放在锁内。

于 2013-03-06T12:38:58.310 回答