C# 在访问ASP.Net缓存项时,下列内容是否会导致竞争条件?

C# 在访问ASP.Net缓存项时,下列内容是否会导致竞争条件?,c#,asp.net,caching,C#,Asp.net,Caching,我正在使用下面的代码,对我来说,下面的代码似乎永远不会出现竞争条件。还是还有机会保持比赛状态 List<Document> listFromCache = Cache[dataCacheName] as List<Document>; if (listFromCache != null) { //do something with listFromCache. **IS IT POSSIBLE** th

我正在使用下面的代码,对我来说,下面的代码似乎永远不会出现竞争条件。还是还有机会保持比赛状态

        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);
        }
List listFromCache=Cache[dataCacheName]作为列表;
if(listFromCache!=null)
{
//对listFromCache执行操作。**是否可能**listFromCache
//此处为空
}
其他的
{
List List=ABC.DataLayer.GetDocuments();
Insert(dataCacheName,list,null,DateTime.Now.AddMinutes(5),
System.Web.Caching.Cache.NoSlidingExpiration);
}
更新: Chris帮我解决了这个问题,但我只是想,我会分享一些对其他人非常有帮助的细节

为了完全避免任何竞争条件,我必须在true部分中添加一个检查,否则,如果在我的if计算为true后,其他人在缓存中清除列表(不是删除该项,而是在缓存中的List对象上调用Clear方法),我可能会得到一个计数为零的列表。因此,在listFromCache对象中,if的真实部分中不会有任何数据

为了克服这个微妙的竞争条件在我的原始代码中,我必须像下面的代码一样仔细检查listFromCache的真实部分,然后用最新的数据重新填充缓存

此外,正如Chris所说,如果其他人通过调用Cache.Remove方法从缓存中“删除”项,则listFromCache不会受到影响,因为垃圾收集器不会从堆内存中删除实际的List对象,因为名为“listFromCache”的变量仍有对它的引用(我在Chris的回复帖子下的评论中对此进行了更详细的解释)

List listFromCache=Cache[dataCacheName]作为列表;
if(listFromCache!=null)
{
//克服一个微妙的种族条件,如果下面
if(listFromCache==null | | listFromCache.Count==0)
{
List List=ABC.DataLayer.GetDocuments();
Insert(dataCacheName,list,null,DateTime.Now.AddMinutes(5),
System.Web.Caching.Cache.NoSlidingExpiration);
}
//现在我确信我的listFromCache包含真实的数据
//对listFromCache执行操作。**是否可能**listFromCache
//此处为空
}
其他的
{
List List=ABC.DataLayer.GetDocuments();
Insert(dataCacheName,list,null,DateTime.Now.AddMinutes(5),
System.Web.Caching.Cache.NoSlidingExpiration);
}

不,在您的注释中,
listFromCache
不可能变为null,因为此时它是一个本地引用。如果缓存项在其他地方为null,则不会影响您的本地引用。但是,您可能会遇到这样一种情况,即在收集文档的过程中检索到null值s(
ABC.DataLayer.GetDocuments()
)另一个进程已经这样做并插入了缓存项,此时您可以覆盖它。(这对您来说可能是完全可以接受的,在这种情况下,太好了!)


您可以尝试使用静态对象锁定它,但老实说,我不确定这在ASP.NET上下文中是否有效。我不记得缓存是在所有ASP.NET进程(IIRC具有不同的静态上下文)之间共享的,还是仅在每个web worker内共享的。如果是后者,则静态锁定可以正常工作

也只是为了证明:

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
    }
}
List listFromCache=Cache[dataCacheName]作为列表;
if(listFromCache!=null)
{
Cache.Remove(dataCacheName);
//listFromCache在此不为空。
if(listFromCache!=null)
{
Console.WriteLine(“NOTNULL!”);//这将运行,因为它不是null
}
}

不,在您的注释中,
listFromCache
不可能变为null,因为此时它是一个本地引用。如果缓存项在其他地方为null,则不会影响您的本地引用。但是,您可能会遇到这样一种情况,即在收集文档的过程中检索到null值s(
ABC.DataLayer.GetDocuments()
)另一个进程已经这样做并插入了缓存项,此时您可以覆盖它。(这对您来说可能是完全可以接受的,在这种情况下,太好了!)


您可以尝试使用静态对象锁定它,但老实说,我不确定这在ASP.NET上下文中是否有效。我不记得缓存是在所有ASP.NET进程(IIRC具有不同的静态上下文)之间共享的,还是仅在每个web worker内共享的。如果是后者,则静态锁定可以正常工作

也只是为了证明:

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
    }
}
List listFromCache=Cache[dataCacheName]作为列表;
if(listFromCache!=null)
{
Cache.Remove(dataCacheName);
//listFromCache在此不为空。
if(listFromCache!=null)
{
Console.WriteLine(“NOTNULL!”);//这将运行,因为它不是null
}
}

否,您的注释中不可能出现
listFromCache
将变为null的情况,因为此时它是一个本地引用。如果缓存项在其他地方为null,则不会影响您的本地引用。但是,您可能会遇到这样的情况,即在收集文档的过程中检索到null值(
ABC.DataLayer.GetDocuments()
)另一个进程已经这样做并插入了缓存项,此时您可以覆盖它。(这对您来说是完全可以接受的,在这种情况下,太好了!)您可以尝试使用静态对象锁定它,但老实说,我不确定这是否适用于ASP.NET上下文。我不记得是在所有ASP.NET进程(IIRC具有不同的静态上下文)中共享
Cache
,还是仅在每个单独的ASP.NET进程中共享