2012-12-01 37 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

相關問題