1

私は次のコードを使用していますが、以下のコードでは競合状態が発生しないようです。または、競合状態の可能性はまだありますか?

        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);
        }

更新: クリスはこの問題の解決を手伝ってくれましたが、他の人にとって非常に役立つ詳細を共有したいと思いました.

競合状態を完全に回避するために、真の部分にチェックを追加する必要がありました。そうしないと、他の誰かがキャッシュでそれをクリアした場合 (アイテムを削除するのではなく、 my if が TRUE と評価された後、キャッシュ内のオブジェクトをリストします。したがって、listFromCache オブジェクトの if の真の部分にはデータがありません。

元のコードのこの微妙な RACE 状態を克服するには、以下のコードのように、実際の部分で listFromCache を再確認してから、キャッシュに最新のデータを再入力する必要があります。

また、Chris が言ったように、誰かが Cache.Remove メソッドを呼び出してキャッシュからアイテムを「削除」した場合、listFromCache は影響を受けません。 listFromCache' はまだそれへの参照を持っています (これについては、Chris の回答投稿の下のコメントで詳しく説明しました)。

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);
    }
4

1 に答える 1

1

listFromCacheいいえ、その時点でローカル参照であるため、コメントでnull になることはできません。キャッシュ エントリが他の場所で無効化されても、ローカル参照には影響しません。ただし、null 値を取得したときに、ドキュメントを収集するプロセス ( 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
    }
}
于 2012-12-01T20:55:17.603 に答える