8

この例外が発生しまし
た 読み取りロックが保持されずに解放されています。
System.Threading.ReaderWriterLockSlim.ExitReadLock() で ..GetBreed(String)

以下は、ロックにアクセスするコード内の唯一の場所です。ご覧のとおり、再帰はありません。この例外がどのように発生するのか理解できません。

static readonly Dictionary<string, BreedOfDog> Breeds 
     = new Dictionary<string,BreedOfDog>();

static BreedOfDog GetBreed(string name)
{
        try
        {
            rwLock.EnterReadLock();
            BreedOfDog bd;
            if (Breeds.TryGetValue(name, out bd))
            {
                return bd;
            }
        }
        finally
        {
            rwLock.ExitReadLock();
        }

        try
        {
            rwLock.EnterWriteLock();
            BreedOfDog bd;
            //make sure it hasn't been added in the interim
            if (Breeds.TryGetValue(t, out bd)
            {
                return bd;
            }
            bd = new BreedOfDog(name); //expensive to fetch all the data needed to run  the constructor, hence the caching

            Breeds[name] = bd;
            return bd;
        }
        finally
        {
            rwLock.ExitWriteLock();
        }
}  
4

2 に答える 2

3

LockRecursionPolicy.SupportsRecursionRWLS をインスタンス化するときに使用します。エラーが解消された場合、実際には何らかの再帰が含まれています。おそらく、投稿していないコードにあるのでしょうか?

そして、これから最大の同時実行性を得ることを本当に心配している場合 (RWLS を使用しているため、そうなると思います)、ダブルチェック ロック パターンを使用できます。元のコードにすでにその感覚があることに気付きましたか? では、なぜ茂みをぶち壊すのですか?早くやれよ。

次のコードでは、参照を常にBreeds不変として扱い、内部で参照lockを再チェック、コピー、変更、およびスワップアウトする方法に注目してください。

static volatile Dictionary<string, BreedOfDog> Breeds = new Dictionary<string,BreedOfDog>();
static readonly object LockObject = new object();

static BreedOfDog GetBreed(string name)
{
  BreedOfDog bd;
  if (!Breeds.TryGetValue(name, out bd))
  {
    lock (LockObject)
    {
      if (!Breeds.TryGetValue(name, out bd))
      {
        bd = new BreedOfDog(name);
        var copy = new Dictionary<string, BreedOfDog>(Breeds);
        copy[name] = bd;
        Breeds = copy;
      }
    }
  }
  return bd;
}
于 2012-04-24T18:48:36.320 に答える
3

再入可能な何かがあり、ロックを取得するときに例外がスローされていると思います。「ロックを取得」、「試行」対「試行」、「ロックを取得」のキャッチ 22 があります。試してみてください」は、強調する必要がない可能性が非常に低いです)。

「ロックを取得」を「試行」の外に移動し、実際の例外が何であるかを確認します。

問題は、ロックの取得に失敗している可能性が高く (おそらく再入可能)、取得していないものをロック解除しようとしています。これは、ロックを取得した元のコードで例外が発生したことを意味している可能性があります。

注: Monitor には、このシナリオに役立つ "ref bool" パラメーターを使用した新しいオーバーロードがありますが、他のロック タイプにはありません。

于 2012-04-24T18:00:44.237 に答える