20

In my code I have a static dictionary object

private static IDictionary< ConnKey, DbConnection > ConnectionList = new Dictionary< ConnKey, DbConnection >( );

which is throwing this error

System.IndexOutOfRangeException: Index was outside the bounds of the array.
  at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
  at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)

I searched and found that this occurs because multiple threads try to access dictionary, but I do have lock on dictionary

lock( ConnectionList ) {
   ConnectionList.Add( key, res );
}

Then I searched more and found that lock on dictionary doesn't prevent all the operations on it so I should be using lock on SyncRoot object of it like this to achieve what I want

lock( ((IDictionary)ConnectionList).SyncRoot) {

But then I searched that using SyncRoot is not a good practice

On further search I found there is a ConcurrentDictionary for this purpose

  1. So can anybody please suggest me which is the best way to lock the dictionary
  2. If I use ConcurrentDictionary do I still need to use lock on it or will it handle everything by itself.
  3. If I have to use lock on ConcurrentDictionary, I have to use lock on it directly or again I have to lock the SyncRoot object for it

Thanks in advance!

4

3 に答える 3

21

Dictionary<,>読み取りと書き込みの両方をロックする必要があります。だから両方

lock( ConnectionList ) {
   ConnectionList.Add( key, res );
}

lock( ConnectionList ) {
   res = ConnectionList[ key ];
}

lock( ConnectionList ) {
   int cnt = ConnectionList.Count;
}

lock( ConnectionList ) {
   ConnectionList.Clear();
}

lock( ConnectionList ) {
   foreach ( var kv in ConnectionList ) {
      // Do things
   }
}

等々 :-)

ConcurrentDictionary<,>ロックは必要ありませんが、構文が次のものとは少し異なることに注意してください。Dictionary<,>

于 2015-04-10T09:21:53.113 に答える
3
  1. 辞書をロックする最良の方法を教えてください。

SyncRoot辞書オブジェクトにアクセスするときにロックするプライベートオブジェクトを使用または作成できます。

private static object _sybcRoot = new object();

public static void Add( string key, string res)
    lock( _sybcRoot ) {
       ConnectionList.Add( key, res );
    }
}

同じリソースへのアクセスを保護するには、同じロック オブジェクトを使用する必要があります。そうしないと、スレッドはリソースが空いていると「考える」可能性がありますが、実際には他のオブジェクトの同期ルートでリソースをロックする他のスレッドによって使用されます。

  1. ConcurrentDictionary を使用する場合、ロックを使用する必要がありますか、それともすべてを単独で処理しますか。

Concurrent*いいえ、コレクションを使用するときにロックする必要はありません。設計上スレッドセーフですが、この構文は少し異なります。Concurrent*コレクションはロックレス アプローチを使用します。これは、アクセスを競合するスレッドが多くない場合に適しています (オプティミスティック コンカレンシー)。

  1. ConcurrentDictionary でロックを使用する必要がある場合は、直接ロックを使用するか、SyncRoot オブジェクトをロックする必要があります。
于 2015-04-10T09:29:49.940 に答える