我正在使用下面的代码,对我来说,似乎竞争条件永远不会发生在下面的代码中。或者仍然有比赛条件的机会?当访问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);
}
不,这不可能在你的评论说,'因为它是在这一点上的本地引用listFromCache'将成为空。如果其他地方的缓存项无效,则不会影响本地参考。但是,您可能会得到一个条件,在该条件下您检索到空值,但在收集文档('ABC.DataLayer.GetDocuments()')的过程中,另一个进程已经完成并插入了缓存条目,你覆盖它。 (这对你来说可能是完全可以接受的,在这种情况下,太棒了!) –
你可以尝试用一个静态对象锁定它,但老实说,我不确定这是否会在ASP.NET上下文中工作。我不记得是否所有ASP.NET进程(IIRC,具有不同的静态上下文)共享“Cache”,或者只在每个Web工作者中共享。如果是后者,静态锁定会正常工作。 –
克里斯 - 感谢您的详细解释。在ASP.Net中缓存安全的,所以如果两个用户插入到缓存中,它将不会发生任何错误。但在我的代码中,如果列表表单缓存不为空,然后在我到达if(而不是其他部分)的真实部分的时候删除缓存项。这是我的担忧。 – Sunil