1

我正在尝试分析我的代码中的不安全线程可能会遇到什么问题。

在我的 mvc3 web 应用程序中,我尝试执行以下操作:

// Caching code
public static class CacheExtensions
{
    public static T GetOrStore<T>(this Cache cache, string key, Func<T> generator)
    {
        var result = cache[key];
        if(result == null)
        {
          result = generator();
          lock(sync) {
              cache[key] = result;
          }
        }
    return (T)result;
    }
}

像这样使用缓存:

// Using the cached stuff
public class SectionViewData 
{
    public IEnumerable<Product> Products {get;set;}
    public IEnumerable<SomethingElse> SomethingElse {get;set;}
}

private void Testing() 
{
    var cachedSection = HttpContext.Current.Cache.GetOrStore("Some Key", 0 => GetSectionViewData());

    // Threading problem?
    foreach(var product in cachedSection.Products)
    {
         DosomestuffwithProduct...
    }
}

private SectionViewData GetSectionViewData() 
{
    SectionViewData viewData = new SectionViewData();
    viewData.Products = CreateProductList();
    viewData.SomethingElse = CreateSomethingElse();

    return viewData;
}

我可以用 IEnumerable 运行 inte 问题吗?我对线程问题没有太多经验。如果其他线程将新值添加到缓存中,cachedSection 不会被触及,对吧?对我来说,这行得通!

我应该单独缓存 Products 和 SomethingElse 吗?这会比缓存整个 SectionViewData 更好吗?

4

2 回答 2

1

线程很难;

在您的GetOrStore方法中,get/generator 序列是完全不同步的,因此任何线程都可以从缓存中获取 null 并同时运行生成器函数。这可能——也可能不是——是个问题。

您的lock语句只锁定了 cache[string] 的设置器,它已经是线程安全的,不需要“额外锁定”。

缓存中双重检查锁定的变化是可疑的,我会尝试摆脱它。由于从不进入 lock() 部分的线程可以在result没有内存屏障的情况result下获得,因此在线程获得它时可能尚未完全构建。

只要没有任何东西同时修改它们,枚举缓存的 IEnumrator 是安全的。如果GetSectionViewData()返回一个具有不可变(如不变)集合的对象,那么您是安全的。

于 2012-10-05T21:44:42.830 回答
0

您的代码缺少部分,例如如何填充产品?仅在 GetSectionViewData 中?如果是这样,那么我认为您的代码没有重大问题。然而,两个线程有​​可能为同一个键生成相同的数据(CachedSection),它不应该产生线程问题,除非你做两次工作,所以如果这是一个昂贵的操作,我会改变代码所以每个密钥只生成一次。如果它不贵,它就可以正常工作。

产品的 IEnumerable 没有被触及(假设您为每个线程单独创建它,但是缓存上的枚举数会针对每个插入操作进行修改,因此它不是线程安全的。所以如果您使用它,我会小心的。

于 2012-10-05T21:41:21.663 回答