私のコードには静的辞書オブジェクトがあります
private static IDictionary< ConnKey, DbConnection > ConnectionList = new Dictionary< ConnKey, DbConnection >( );
これはこのエラーをスローしています
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)
検索したところ、複数のスレッドが辞書にアクセスしようとしたことが原因であることがわかりましたが、辞書にはlock
があります
lock( ConnectionList ) {
ConnectionList.Add( key, res );
}
次に、さらに検索したところ、ディクショナリをロックしてもそのすべての操作が妨げられないことがわかったので、このようなlock
オブジェクトに対してSyncRoot
を使用して、目的の結果を得る必要があります。
lock( ((IDictionary)ConnectionList).SyncRoot) {
しかし、SyncRoot
を使用することは良い習慣ではないことを検索しました
さらに検索したところ、この目的のためにConcurrentDictionary
があることがわかりました
ConcurrentDictionary
を使用する場合でも、lock
を使用する必要がありますか、それともすべてを単独で処理しますか?.ConcurrentDictionary
でロックを使用する必要がある場合は、lock
を直接使用するか、SyncRoot
オブジェクトをロックする必要があります前もって感謝します!
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<,>
の構文と少し異なることに注意してください。
それで、誰が私に辞書をロックする最善の方法が私に提案することができますか?
従来のDictionary<,>
AFAKを引き続き使用する場合は、辞書によって実装されているICollection
インターフェイスを調べ、プロパティ ICollection.SyncRoot
を使用する必要があります。
[〜#〜] msdn [〜#〜]Gets an object that can be used to synchronize access to the ICollection.
これを達成するにはあなたはこのようなことをすることができます
ConcurrentDictionaryを使用する場合でも、ロックを使用する必要がありますか、それともすべてを単独で処理しますか?.
From [〜#〜] msdn [〜#〜]
ConcurrentDictionaryはマルチスレッドシナリオ用に設計されています。コレクションの項目を追加または削除するためにコードでロックを使用する必要はありません。ただし、1つのスレッドが常に値を取得し、別のスレッドが同じキーに新しい値を与えることでコレクションをすぐに更新することは常に可能です。
ConcurrentDictionaryでロックを使用する必要がある場合は、直接ロックするか、もう一度SyncRootオブジェクトをロックする必要があります。
はい、lock
またはSyncRoot
メソッドを使用するときにアトミックメソッドを実行する場合は、GetOrAdd
でAddOrUpdate
を使用する必要があります。
- だから誰も私に辞書をロックする最善の方法を教えてください
SyncRoot
を使用するか、ディクショナリオブジェクトにアクセスするときにロックするプライベートオブジェクトを作成できます。
private static object _sybcRoot = new object();
public static void Add( string key, string res)
lock( _sybcRoot ) {
ConnectionList.Add( key, res );
}
}
- ConcurrentDictionaryを使用する場合でも、ロックを使用する必要がありますか、それともすべてを単独で処理しますか?.
いいえ、Concurrent*
コレクションを使用する場合はロックする必要はありません。設計上はスレッドセーフですが、この構文は少し異なります。 Concurrent*
コレクションはロックレスアプローチを使用します。これは、アクセスを競合するスレッドが多くない場合に最適です(楽観的同時実行性)
- ConcurrentDictionaryでロックを使用する必要がある場合は、直接ロックするか、もう一度SyncRootオブジェクトをロックする必要があります。
同じロックオブジェクトを使用して、同じリソースへのアクセスを保護する必要があります。そうでない場合、スレッドはリソースが解放されていると「考える」可能性がありますが、実際には、他のオブジェクトの同期ルートでたまたまロックする他のスレッドによって使用されています。