2012-12-01 33 views
1

我正在使用下面的代码,对我来说,似乎竞争条件永远不会发生在下面的代码中。或者仍然有比赛条件的机会?当访问ASP.Net Cache项目时,会继续导致RACE CONDITION吗?

 List<Document> listFromCache = Cache[dataCacheName] as List<Document>; 
     if (listFromCache != null) 
     { 
      //do something with listFromCache. **IS IT POSSIBLE** that listFromCache is 
               //NULL here 
     } 
     else 
     { 
      List<Document> list = ABC.DataLayer.GetDocuments(); 
      Cache.Insert(dataCacheName, list, null, DateTime.Now.AddMinutes(5), 
          System.Web.Caching.Cache.NoSlidingExpiration); 
     } 

UPDATE: 克里斯帮我解决这个问题,但我只是想,我会分享一些细节会被他人非常有帮助。为了完全避免任何竞争条件,我必须在真实部分中添加一个检查,否则,如果有其他人在缓存中清除了它,我可以以零计数结束List(不删除该项目,而只是调用在我的if已经评估为TRUE之后,在Cache中的List对象上清除方法)。那么,如果在listFromCache对象中,我的真实部分中不会有任何数据。

克服的,在我的原代码,这种微妙的竞争条件,我必须仔细的真实部分检查listFromCache如下面的代码,然后用最新数据重新填充缓存。

而且,克里斯说,如果别人通过调用方法Cache.Remove“删除”从缓存中的项目,然后将listFromCache不影响,因为垃圾收集器将不会从HEAP删除实际List对象因为名为“listFromCache”的变量仍然有一个引用它(我已经在克里斯的回答帖子下的评论中更详细地解释了这一点)。

List<Document> listFromCache = Cache[dataCacheName] as List<Document>; 
    if (listFromCache != null) 
    { 
     //OVERCOME A SUBTLE RACE CONDITION BY IF BELOW 
     if(listFromCache == null || listFromCache.Count == 0) 
     { 
      List<Document> list = ABC.DataLayer.GetDocuments(); 
      Cache.Insert(dataCacheName, list, null, DateTime.Now.AddMinutes(5), 
         System.Web.Caching.Cache.NoSlidingExpiration); 
     } 
     //NOW I AM SURE MY listFromCache contains true data 
     //do something with listFromCache. **IS IT POSSIBLE** that listFromCache is 
              //NULL here 
    } 
    else 
    { 
     List<Document> list = ABC.DataLayer.GetDocuments(); 
     Cache.Insert(dataCacheName, list, null, DateTime.Now.AddMinutes(5), 
         System.Web.Caching.Cache.NoSlidingExpiration); 
    } 
+0

不,这不可能在你的评论说,'因为它是在这一点上的本地引用listFromCache'将成为空。如果其他地方的缓存项无效,则不会影响本地参考。但是,您可能会得到一个条件,在该条件下您检索到空值,但在收集文档('ABC.DataLayer.GetDocuments()')的过程中,另一个进程已经完成并插入了缓存条目,你覆盖它。 (这对你来说可能是完全可以接受的,在这种情况下,太棒了!) –

+0

你可以尝试用一个静态对象锁定它,但老实说,我不确定这是否会在ASP.NET上下文中工作。我不记得是否所有ASP.NET进程(IIRC,具有不同的静态上下文)共享“Cache”,或者只在每个Web工作者中共享。如果是后者,静态锁定会正常工作。 –

+0

克里斯 - 感谢您的详细解释。在ASP.Net中缓存安全的,所以如果两个用户插入到缓存中,它将不会发生任何错误。但在我的代码中,如果列表表单缓存不为空,然后在我到达if(而不是其他部分)的真实部分的时候删除缓存项。这是我的担忧。 – Sunil

回答

1

不,这不是在您的评论可能是因为它是在这一点上的本地引用listFromCache将成为空。如果其他地方的缓存项无效,则不会影响本地参考。但是,您可能会得到一个检索空值的条件,但在收集文档(ABC.DataLayer.GetDocuments())的过程中,另一个进程已经完成并插入了缓存条目,此时您将其覆盖。 (这可能是完全可以接受的,在这种情况下,太好了!)

你可以尝试用静态对象锁定它,但老实说,我不确定这是否会在ASP.NET上下文中工作。我不记得缓存是否跨所有ASP.NET进程(IIRC,具有不同的静态上下文)共享,或者只在每个Web工作者中共享。如果是后者,静态锁定会正常工作。

只是为了演示过:

List<Document> listFromCache = Cache[dataCacheName] as List<Document>; 
if (listFromCache != null) 
{ 
    Cache.Remove(dataCacheName); 
    //listFromCache will NOT be null here. 
    if (listFromCache != null) 
    { 
     Console.WriteLine("Not null!"); //this will run because it's not null 
    } 
} 
+0

克里斯 - 感谢。我即将尝试你的片段。谢谢。 – Sunil

+0

@Sunil我犯了一个非常重大的错字,但我想你会发现它很容易。 (我有'listFromCache.Remove(dataCacheName)'而不是'Cache.Remove(dataCacheName)') –

+0

Chris - 刚试过你的代码片段,它没有问题。所以它似乎listFromCache指向它自己的副本的列表对象,而不是缓存中的项目。对? – Sunil

相关问题