mscorlib(4.0.0.0) API with additions
ConcurrentDictionary.cs
3 using System.Diagnostics;
7 using System.Threading;
8 
10 {
14  [Serializable]
15  [ComVisible(false)]
16  [DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<, >))]
17  [DebuggerDisplay("Count = {Count}")]
18  [__DynamicallyInvokable]
19  [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
20  public class ConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary, ICollection, IReadOnlyDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>
21  {
22  private class Tables
23  {
24  internal readonly Node[] m_buckets;
25 
26  internal readonly object[] m_locks;
27 
28  internal volatile int[] m_countPerLock;
29 
30  internal readonly IEqualityComparer<TKey> m_comparer;
31 
32  internal Tables(Node[] buckets, object[] locks, int[] countPerLock, IEqualityComparer<TKey> comparer)
33  {
34  m_buckets = buckets;
35  m_locks = locks;
36  m_countPerLock = countPerLock;
37  m_comparer = comparer;
38  }
39  }
40 
41  private class Node
42  {
43  internal TKey m_key;
44 
45  internal TValue m_value;
46 
47  internal volatile Node m_next;
48 
49  internal int m_hashcode;
50 
51  internal Node(TKey key, TValue value, int hashcode, Node next)
52  {
53  m_key = key;
54  m_value = value;
55  m_next = next;
56  m_hashcode = hashcode;
57  }
58  }
59 
60  private class DictionaryEnumerator : IDictionaryEnumerator, IEnumerator
61  {
62  private IEnumerator<KeyValuePair<TKey, TValue>> m_enumerator;
63 
64  public DictionaryEntry Entry => new DictionaryEntry(m_enumerator.Current.Key, m_enumerator.Current.Value);
65 
66  public object Key => m_enumerator.Current.Key;
67 
68  public object Value => m_enumerator.Current.Value;
69 
70  public object Current => Entry;
71 
72  internal DictionaryEnumerator(ConcurrentDictionary<TKey, TValue> dictionary)
73  {
74  m_enumerator = dictionary.GetEnumerator();
75  }
76 
77  public bool MoveNext()
78  {
79  return m_enumerator.MoveNext();
80  }
81 
82  public void Reset()
83  {
84  m_enumerator.Reset();
85  }
86  }
87 
88  [NonSerialized]
89  private volatile Tables m_tables;
90 
91  internal IEqualityComparer<TKey> m_comparer;
92 
93  [NonSerialized]
94  private readonly bool m_growLockArray;
95 
96  [OptionalField]
97  private int m_keyRehashCount;
98 
99  [NonSerialized]
100  private int m_budget;
101 
102  private KeyValuePair<TKey, TValue>[] m_serializationArray;
103 
104  private int m_serializationConcurrencyLevel;
105 
106  private int m_serializationCapacity;
107 
108  private const int DEFAULT_CONCURRENCY_MULTIPLIER = 4;
109 
110  private const int DEFAULT_CAPACITY = 31;
111 
112  private const int MAX_LOCK_NUMBER = 1024;
113 
114  private static readonly bool s_isValueWriteAtomic = IsValueWriteAtomic();
115 
122  [__DynamicallyInvokable]
123  public TValue this[TKey key]
124  {
125  [__DynamicallyInvokable]
126  get
127  {
128  if (!TryGetValue(key, out TValue value))
129  {
130  throw new KeyNotFoundException();
131  }
132  return value;
133  }
134  [__DynamicallyInvokable]
135  set
136  {
137  if (key == null)
138  {
139  throw new ArgumentNullException("key");
140  }
141  TryAddInternal(key, value, updateIfExists: true, acquireLock: true, out TValue _);
142  }
143  }
144 
148  [__DynamicallyInvokable]
149  public int Count
150  {
151  [__DynamicallyInvokable]
152  get
153  {
154  int num = 0;
155  int locksAcquired = 0;
156  try
157  {
158  AcquireAllLocks(ref locksAcquired);
159  for (int i = 0; i < m_tables.m_countPerLock.Length; i++)
160  {
161  num += m_tables.m_countPerLock[i];
162  }
163  return num;
164  }
165  finally
166  {
167  ReleaseLocks(0, locksAcquired);
168  }
169  }
170  }
171 
175  [__DynamicallyInvokable]
176  public bool IsEmpty
177  {
178  [__DynamicallyInvokable]
179  get
180  {
181  int locksAcquired = 0;
182  try
183  {
184  AcquireAllLocks(ref locksAcquired);
185  for (int i = 0; i < m_tables.m_countPerLock.Length; i++)
186  {
187  if (m_tables.m_countPerLock[i] != 0)
188  {
189  return false;
190  }
191  }
192  }
193  finally
194  {
195  ReleaseLocks(0, locksAcquired);
196  }
197  return true;
198  }
199  }
200 
203  [__DynamicallyInvokable]
204  public ICollection<TKey> Keys
205  {
206  [__DynamicallyInvokable]
207  get
208  {
209  return GetKeys();
210  }
211  }
212 
213  [__DynamicallyInvokable]
215  {
216  [__DynamicallyInvokable]
217  get
218  {
219  return GetKeys();
220  }
221  }
222 
225  [__DynamicallyInvokable]
227  {
228  [__DynamicallyInvokable]
229  get
230  {
231  return GetValues();
232  }
233  }
234 
235  [__DynamicallyInvokable]
237  {
238  [__DynamicallyInvokable]
239  get
240  {
241  return GetValues();
242  }
243  }
244 
245  [__DynamicallyInvokable]
247  {
248  [__DynamicallyInvokable]
249  get
250  {
251  return false;
252  }
253  }
254 
258  [__DynamicallyInvokable]
259  bool IDictionary.IsFixedSize
260  {
261  [__DynamicallyInvokable]
262  get
263  {
264  return false;
265  }
266  }
267 
271  [__DynamicallyInvokable]
272  bool IDictionary.IsReadOnly
273  {
274  [__DynamicallyInvokable]
275  get
276  {
277  return false;
278  }
279  }
280 
283  [__DynamicallyInvokable]
285  {
286  [__DynamicallyInvokable]
287  get
288  {
289  return GetKeys();
290  }
291  }
292 
295  [__DynamicallyInvokable]
297  {
298  [__DynamicallyInvokable]
299  get
300  {
301  return GetValues();
302  }
303  }
304 
311  [__DynamicallyInvokable]
312  object IDictionary.this[object key]
313  {
314  [__DynamicallyInvokable]
315  get
316  {
317  if (key == null)
318  {
319  throw new ArgumentNullException("key");
320  }
321  if (key is TKey && TryGetValue((TKey)key, out TValue value))
322  {
323  return value;
324  }
325  return null;
326  }
327  [__DynamicallyInvokable]
328  set
329  {
330  if (key == null)
331  {
332  throw new ArgumentNullException("key");
333  }
334  if (!(key is TKey))
335  {
336  throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfKeyIncorrect"));
337  }
338  if (!(value is TValue))
339  {
340  throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfValueIncorrect"));
341  }
342  this[(TKey)key] = (TValue)value;
343  }
344  }
345 
349  [__DynamicallyInvokable]
350  bool ICollection.IsSynchronized
351  {
352  [__DynamicallyInvokable]
353  get
354  {
355  return false;
356  }
357  }
358 
362  [__DynamicallyInvokable]
363  object ICollection.SyncRoot
364  {
365  [__DynamicallyInvokable]
366  get
367  {
368  throw new NotSupportedException(Environment.GetResourceString("ConcurrentCollection_SyncRoot_NotSupported"));
369  }
370  }
371 
372  private static int DefaultConcurrencyLevel => 4 * PlatformHelper.ProcessorCount;
373 
374  private static bool IsValueWriteAtomic()
375  {
376  Type typeFromHandle = typeof(TValue);
377  bool flag = typeFromHandle.IsClass || typeFromHandle == typeof(bool) || typeFromHandle == typeof(char) || typeFromHandle == typeof(byte) || typeFromHandle == typeof(sbyte) || typeFromHandle == typeof(short) || typeFromHandle == typeof(ushort) || typeFromHandle == typeof(int) || typeFromHandle == typeof(uint) || typeFromHandle == typeof(float);
378  if (!flag && IntPtr.Size == 8)
379  {
380  flag |= (typeFromHandle == typeof(double) || typeFromHandle == typeof(long));
381  }
382  return flag;
383  }
384 
386  [__DynamicallyInvokable]
388  : this(DefaultConcurrencyLevel, 31, growLockArray: true, (IEqualityComparer<TKey>)EqualityComparer<TKey>.Default)
389  {
390  }
391 
398  [__DynamicallyInvokable]
399  public ConcurrentDictionary(int concurrencyLevel, int capacity)
400  : this(concurrencyLevel, capacity, growLockArray: false, (IEqualityComparer<TKey>)EqualityComparer<TKey>.Default)
401  {
402  }
403 
410  [__DynamicallyInvokable]
412  : this(collection, (IEqualityComparer<TKey>)EqualityComparer<TKey>.Default)
413  {
414  }
415 
420  [__DynamicallyInvokable]
422  : this(DefaultConcurrencyLevel, 31, growLockArray: true, comparer)
423  {
424  }
425 
431  [__DynamicallyInvokable]
433  : this(comparer)
434  {
435  if (collection == null)
436  {
437  throw new ArgumentNullException("collection");
438  }
439  InitializeFromCollection(collection);
440  }
441 
452  [__DynamicallyInvokable]
453  public ConcurrentDictionary(int concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer)
454  : this(concurrencyLevel, 31, growLockArray: false, comparer)
455  {
456  if (collection == null)
457  {
458  throw new ArgumentNullException("collection");
459  }
460  if (comparer == null)
461  {
462  throw new ArgumentNullException("comparer");
463  }
464  InitializeFromCollection(collection);
465  }
466 
467  private void InitializeFromCollection(IEnumerable<KeyValuePair<TKey, TValue>> collection)
468  {
469  foreach (KeyValuePair<TKey, TValue> item in collection)
470  {
471  if (item.Key == null)
472  {
473  throw new ArgumentNullException("key");
474  }
475  if (!TryAddInternal(item.Key, item.Value, updateIfExists: false, acquireLock: false, out TValue _))
476  {
477  throw new ArgumentException(GetResource("ConcurrentDictionary_SourceContainsDuplicateKeys"));
478  }
479  }
480  if (m_budget == 0)
481  {
482  m_budget = m_tables.m_buckets.Length / m_tables.m_locks.Length;
483  }
484  }
485 
494  [__DynamicallyInvokable]
495  public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer)
496  : this(concurrencyLevel, capacity, growLockArray: false, comparer)
497  {
498  }
499 
500  internal ConcurrentDictionary(int concurrencyLevel, int capacity, bool growLockArray, IEqualityComparer<TKey> comparer)
501  {
502  if (concurrencyLevel < 1)
503  {
504  throw new ArgumentOutOfRangeException("concurrencyLevel", GetResource("ConcurrentDictionary_ConcurrencyLevelMustBePositive"));
505  }
506  if (capacity < 0)
507  {
508  throw new ArgumentOutOfRangeException("capacity", GetResource("ConcurrentDictionary_CapacityMustNotBeNegative"));
509  }
510  if (comparer == null)
511  {
512  throw new ArgumentNullException("comparer");
513  }
514  if (capacity < concurrencyLevel)
515  {
516  capacity = concurrencyLevel;
517  }
518  object[] array = new object[concurrencyLevel];
519  for (int i = 0; i < array.Length; i++)
520  {
521  array[i] = new object();
522  }
523  int[] countPerLock = new int[array.Length];
524  Node[] array2 = new Node[capacity];
525  m_tables = new Tables(array2, array, countPerLock, comparer);
526  m_growLockArray = growLockArray;
527  m_budget = array2.Length / array.Length;
528  }
529 
538  [__DynamicallyInvokable]
539  public bool TryAdd(TKey key, TValue value)
540  {
541  if (key == null)
542  {
543  throw new ArgumentNullException("key");
544  }
545  TValue resultingValue;
546  return TryAddInternal(key, value, updateIfExists: false, acquireLock: true, out resultingValue);
547  }
548 
555  [__DynamicallyInvokable]
556  public bool ContainsKey(TKey key)
557  {
558  if (key == null)
559  {
560  throw new ArgumentNullException("key");
561  }
562  TValue value;
563  return TryGetValue(key, out value);
564  }
565 
573  [__DynamicallyInvokable]
574  public bool TryRemove(TKey key, out TValue value)
575  {
576  if (key == null)
577  {
578  throw new ArgumentNullException("key");
579  }
580  return TryRemoveInternal(key, out value, matchValue: false, default(TValue));
581  }
582 
583  private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue)
584  {
585  while (true)
586  {
587  Tables tables = m_tables;
588  IEqualityComparer<TKey> comparer = tables.m_comparer;
589  GetBucketAndLockNo(comparer.GetHashCode(key), out int bucketNo, out int lockNo, tables.m_buckets.Length, tables.m_locks.Length);
590  lock (tables.m_locks[lockNo])
591  {
592  if (tables == m_tables)
593  {
594  Node node = null;
595  for (Node node2 = tables.m_buckets[bucketNo]; node2 != null; node2 = node2.m_next)
596  {
597  if (comparer.Equals(node2.m_key, key))
598  {
599  if (matchValue && !EqualityComparer<TValue>.Default.Equals(oldValue, node2.m_value))
600  {
601  value = default(TValue);
602  return false;
603  }
604  if (node == null)
605  {
606  Volatile.Write(ref tables.m_buckets[bucketNo], node2.m_next);
607  }
608  else
609  {
610  node.m_next = node2.m_next;
611  }
612  value = node2.m_value;
613  tables.m_countPerLock[lockNo]--;
614  return true;
615  }
616  node = node2;
617  }
618  break;
619  }
620  }
621  }
622  value = default(TValue);
623  return false;
624  }
625 
633  [__DynamicallyInvokable]
634  public bool TryGetValue(TKey key, out TValue value)
635  {
636  if (key == null)
637  {
638  throw new ArgumentNullException("key");
639  }
640  Tables tables = m_tables;
641  IEqualityComparer<TKey> comparer = tables.m_comparer;
642  GetBucketAndLockNo(comparer.GetHashCode(key), out int bucketNo, out int _, tables.m_buckets.Length, tables.m_locks.Length);
643  for (Node node = Volatile.Read(ref tables.m_buckets[bucketNo]); node != null; node = node.m_next)
644  {
645  if (comparer.Equals(node.m_key, key))
646  {
647  value = node.m_value;
648  return true;
649  }
650  }
651  value = default(TValue);
652  return false;
653  }
654 
663  [__DynamicallyInvokable]
664  public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue)
665  {
666  if (key == null)
667  {
668  throw new ArgumentNullException("key");
669  }
671  while (true)
672  {
673  Tables tables = m_tables;
674  IEqualityComparer<TKey> comparer = tables.m_comparer;
675  int hashCode = comparer.GetHashCode(key);
676  GetBucketAndLockNo(hashCode, out int bucketNo, out int lockNo, tables.m_buckets.Length, tables.m_locks.Length);
677  lock (tables.m_locks[lockNo])
678  {
679  if (tables == m_tables)
680  {
681  Node node = null;
682  for (Node node2 = tables.m_buckets[bucketNo]; node2 != null; node2 = node2.m_next)
683  {
684  if (comparer.Equals(node2.m_key, key))
685  {
686  if (@default.Equals(node2.m_value, comparisonValue))
687  {
688  if (s_isValueWriteAtomic)
689  {
690  node2.m_value = newValue;
691  }
692  else
693  {
694  Node node3 = new Node(node2.m_key, newValue, hashCode, node2.m_next);
695  if (node == null)
696  {
697  tables.m_buckets[bucketNo] = node3;
698  }
699  else
700  {
701  node.m_next = node3;
702  }
703  }
704  return true;
705  }
706  return false;
707  }
708  node = node2;
709  }
710  return false;
711  }
712  }
713  }
714  }
715 
717  [__DynamicallyInvokable]
718  public void Clear()
719  {
720  int locksAcquired = 0;
721  try
722  {
723  AcquireAllLocks(ref locksAcquired);
724  Tables tables = m_tables = new Tables(new Node[31], m_tables.m_locks, new int[m_tables.m_countPerLock.Length], m_tables.m_comparer);
725  m_budget = Math.Max(1, tables.m_buckets.Length / tables.m_locks.Length);
726  }
727  finally
728  {
729  ReleaseLocks(0, locksAcquired);
730  }
731  }
732 
733  [__DynamicallyInvokable]
735  {
736  if (array == null)
737  {
738  throw new ArgumentNullException("array");
739  }
740  if (index < 0)
741  {
742  throw new ArgumentOutOfRangeException("index", GetResource("ConcurrentDictionary_IndexIsNegative"));
743  }
744  int locksAcquired = 0;
745  try
746  {
747  AcquireAllLocks(ref locksAcquired);
748  int num = 0;
749  for (int i = 0; i < m_tables.m_locks.Length; i++)
750  {
751  if (num < 0)
752  {
753  break;
754  }
755  num += m_tables.m_countPerLock[i];
756  }
757  if (array.Length - num < index || num < 0)
758  {
759  throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayNotLargeEnough"));
760  }
761  CopyToPairs(array, index);
762  }
763  finally
764  {
765  ReleaseLocks(0, locksAcquired);
766  }
767  }
768 
771  [__DynamicallyInvokable]
773  {
774  int locksAcquired = 0;
775  checked
776  {
777  try
778  {
779  AcquireAllLocks(ref locksAcquired);
780  int num = 0;
781  for (int i = 0; i < m_tables.m_locks.Length; i++)
782  {
783  num += m_tables.m_countPerLock[i];
784  }
786  CopyToPairs(array, 0);
787  return array;
788  }
789  finally
790  {
791  ReleaseLocks(0, locksAcquired);
792  }
793  }
794  }
795 
796  private void CopyToPairs(KeyValuePair<TKey, TValue>[] array, int index)
797  {
798  Node[] buckets = m_tables.m_buckets;
799  for (int i = 0; i < buckets.Length; i++)
800  {
801  for (Node node = buckets[i]; node != null; node = node.m_next)
802  {
803  array[index] = new KeyValuePair<TKey, TValue>(node.m_key, node.m_value);
804  index++;
805  }
806  }
807  }
808 
809  private void CopyToEntries(DictionaryEntry[] array, int index)
810  {
811  Node[] buckets = m_tables.m_buckets;
812  for (int i = 0; i < buckets.Length; i++)
813  {
814  for (Node node = buckets[i]; node != null; node = node.m_next)
815  {
816  array[index] = new DictionaryEntry(node.m_key, node.m_value);
817  index++;
818  }
819  }
820  }
821 
822  private void CopyToObjects(object[] array, int index)
823  {
824  Node[] buckets = m_tables.m_buckets;
825  for (int i = 0; i < buckets.Length; i++)
826  {
827  for (Node node = buckets[i]; node != null; node = node.m_next)
828  {
829  array[index] = new KeyValuePair<TKey, TValue>(node.m_key, node.m_value);
830  index++;
831  }
832  }
833  }
834 
837  [__DynamicallyInvokable]
839  {
840  Node[] buckets = m_tables.m_buckets;
841  for (int i = 0; i < buckets.Length; i++)
842  {
843  for (Node current = Volatile.Read(ref buckets[i]); current != null; current = current.m_next)
844  {
845  yield return new KeyValuePair<TKey, TValue>(current.m_key, current.m_value);
846  }
847  }
848  }
849 
850  private bool TryAddInternal(TKey key, TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue)
851  {
852  Tables tables;
853  IEqualityComparer<TKey> comparer;
854  bool flag;
855  bool flag2;
856  while (true)
857  {
858  tables = m_tables;
859  comparer = tables.m_comparer;
860  int hashCode = comparer.GetHashCode(key);
861  GetBucketAndLockNo(hashCode, out int bucketNo, out int lockNo, tables.m_buckets.Length, tables.m_locks.Length);
862  flag = false;
863  bool lockTaken = false;
864  flag2 = false;
865  try
866  {
867  if (acquireLock)
868  {
869  Monitor.Enter(tables.m_locks[lockNo], ref lockTaken);
870  }
871  if (tables == m_tables)
872  {
873  int num = 0;
874  Node node = null;
875  for (Node node2 = tables.m_buckets[bucketNo]; node2 != null; node2 = node2.m_next)
876  {
877  if (comparer.Equals(node2.m_key, key))
878  {
879  if (updateIfExists)
880  {
881  if (s_isValueWriteAtomic)
882  {
883  node2.m_value = value;
884  }
885  else
886  {
887  Node node3 = new Node(node2.m_key, value, hashCode, node2.m_next);
888  if (node == null)
889  {
890  tables.m_buckets[bucketNo] = node3;
891  }
892  else
893  {
894  node.m_next = node3;
895  }
896  }
897  resultingValue = value;
898  }
899  else
900  {
901  resultingValue = node2.m_value;
902  }
903  return false;
904  }
905  node = node2;
906  num++;
907  }
908  if (num > 100 && HashHelpers.IsWellKnownEqualityComparer(comparer))
909  {
910  flag = true;
911  flag2 = true;
912  }
913  Volatile.Write(ref tables.m_buckets[bucketNo], new Node(key, value, hashCode, tables.m_buckets[bucketNo]));
914  checked
915  {
916  tables.m_countPerLock[lockNo]++;
917  if (tables.m_countPerLock[lockNo] > m_budget)
918  {
919  flag = true;
920  }
921  break;
922  }
923  }
924  }
925  finally
926  {
927  if (lockTaken)
928  {
929  Monitor.Exit(tables.m_locks[lockNo]);
930  }
931  }
932  }
933  if (flag)
934  {
935  if (flag2)
936  {
937  GrowTable(tables, (IEqualityComparer<TKey>)HashHelpers.GetRandomizedEqualityComparer(comparer), regenerateHashKeys: true, m_keyRehashCount);
938  }
939  else
940  {
941  GrowTable(tables, tables.m_comparer, regenerateHashKeys: false, m_keyRehashCount);
942  }
943  }
944  resultingValue = value;
945  return true;
946  }
947 
955  [__DynamicallyInvokable]
956  public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
957  {
958  if (key == null)
959  {
960  throw new ArgumentNullException("key");
961  }
962  if (valueFactory == null)
963  {
964  throw new ArgumentNullException("valueFactory");
965  }
966  if (TryGetValue(key, out TValue value))
967  {
968  return value;
969  }
970  TryAddInternal(key, valueFactory(key), updateIfExists: false, acquireLock: true, out value);
971  return value;
972  }
973 
981  [__DynamicallyInvokable]
982  public TValue GetOrAdd(TKey key, TValue value)
983  {
984  if (key == null)
985  {
986  throw new ArgumentNullException("key");
987  }
988  TryAddInternal(key, value, updateIfExists: false, acquireLock: true, out TValue resultingValue);
989  return resultingValue;
990  }
991 
1000  [__DynamicallyInvokable]
1001  public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory)
1002  {
1003  if (key == null)
1004  {
1005  throw new ArgumentNullException("key");
1006  }
1007  if (addValueFactory == null)
1008  {
1009  throw new ArgumentNullException("addValueFactory");
1010  }
1011  if (updateValueFactory == null)
1012  {
1013  throw new ArgumentNullException("updateValueFactory");
1014  }
1015  TValue resultingValue;
1016  while (true)
1017  {
1018  if (TryGetValue(key, out TValue value))
1019  {
1020  TValue val = updateValueFactory(key, value);
1021  if (TryUpdate(key, val, value))
1022  {
1023  return val;
1024  }
1025  }
1026  else
1027  {
1028  TValue val = addValueFactory(key);
1029  if (TryAddInternal(key, val, updateIfExists: false, acquireLock: true, out resultingValue))
1030  {
1031  break;
1032  }
1033  }
1034  }
1035  return resultingValue;
1036  }
1037 
1046  [__DynamicallyInvokable]
1047  public TValue AddOrUpdate(TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory)
1048  {
1049  if (key == null)
1050  {
1051  throw new ArgumentNullException("key");
1052  }
1053  if (updateValueFactory == null)
1054  {
1055  throw new ArgumentNullException("updateValueFactory");
1056  }
1057  TValue resultingValue;
1058  while (true)
1059  {
1060  if (TryGetValue(key, out TValue value))
1061  {
1062  TValue val = updateValueFactory(key, value);
1063  if (TryUpdate(key, val, value))
1064  {
1065  return val;
1066  }
1067  }
1068  else if (TryAddInternal(key, addValue, updateIfExists: false, acquireLock: true, out resultingValue))
1069  {
1070  break;
1071  }
1072  }
1073  return resultingValue;
1074  }
1075 
1076  [__DynamicallyInvokable]
1077  void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
1078  {
1079  if (!TryAdd(key, value))
1080  {
1081  throw new ArgumentException(GetResource("ConcurrentDictionary_KeyAlreadyExisted"));
1082  }
1083  }
1084 
1085  [__DynamicallyInvokable]
1086  bool IDictionary<TKey, TValue>.Remove(TKey key)
1087  {
1088  TValue value;
1089  return TryRemove(key, out value);
1090  }
1091 
1092  [__DynamicallyInvokable]
1094  {
1095  ((IDictionary<TKey, TValue>)this).Add(keyValuePair.Key, keyValuePair.Value);
1096  }
1097 
1098  [__DynamicallyInvokable]
1100  {
1101  if (!TryGetValue(keyValuePair.Key, out TValue value))
1102  {
1103  return false;
1104  }
1105  return EqualityComparer<TValue>.Default.Equals(value, keyValuePair.Value);
1106  }
1107 
1108  [__DynamicallyInvokable]
1110  {
1111  if (keyValuePair.Key == null)
1112  {
1113  throw new ArgumentNullException(GetResource("ConcurrentDictionary_ItemKeyIsNull"));
1114  }
1115  TValue value;
1116  return TryRemoveInternal(keyValuePair.Key, out value, matchValue: true, keyValuePair.Value);
1117  }
1118 
1121  [__DynamicallyInvokable]
1123  {
1124  return GetEnumerator();
1125  }
1126 
1136  [__DynamicallyInvokable]
1137  void IDictionary.Add(object key, object value)
1138  {
1139  if (key == null)
1140  {
1141  throw new ArgumentNullException("key");
1142  }
1143  if (!(key is TKey))
1144  {
1145  throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfKeyIncorrect"));
1146  }
1147  TValue value2;
1148  try
1149  {
1150  value2 = (TValue)value;
1151  }
1152  catch (InvalidCastException)
1153  {
1154  throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfValueIncorrect"));
1155  }
1156  ((IDictionary<TKey, TValue>)this).Add((TKey)key, value2);
1157  }
1158 
1165  [__DynamicallyInvokable]
1166  bool IDictionary.Contains(object key)
1167  {
1168  if (key == null)
1169  {
1170  throw new ArgumentNullException("key");
1171  }
1172  if (key is TKey)
1173  {
1174  return ContainsKey((TKey)key);
1175  }
1176  return false;
1177  }
1178 
1181  [__DynamicallyInvokable]
1182  IDictionaryEnumerator IDictionary.GetEnumerator()
1183  {
1184  return new DictionaryEnumerator(this);
1185  }
1186 
1191  [__DynamicallyInvokable]
1192  void IDictionary.Remove(object key)
1193  {
1194  if (key == null)
1195  {
1196  throw new ArgumentNullException("key");
1197  }
1198  if (key is TKey)
1199  {
1200  TryRemove((TKey)key, out TValue _);
1201  }
1202  }
1203 
1213  [__DynamicallyInvokable]
1214  void ICollection.CopyTo(Array array, int index)
1215  {
1216  if (array == null)
1217  {
1218  throw new ArgumentNullException("array");
1219  }
1220  if (index < 0)
1221  {
1222  throw new ArgumentOutOfRangeException("index", GetResource("ConcurrentDictionary_IndexIsNegative"));
1223  }
1224  int locksAcquired = 0;
1225  try
1226  {
1227  AcquireAllLocks(ref locksAcquired);
1228  Tables tables = m_tables;
1229  int num = 0;
1230  for (int i = 0; i < tables.m_locks.Length; i++)
1231  {
1232  if (num < 0)
1233  {
1234  break;
1235  }
1236  num += tables.m_countPerLock[i];
1237  }
1238  if (array.Length - num < index || num < 0)
1239  {
1240  throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayNotLargeEnough"));
1241  }
1243  if (array2 != null)
1244  {
1245  CopyToPairs(array2, index);
1246  }
1247  else
1248  {
1249  DictionaryEntry[] array3 = array as DictionaryEntry[];
1250  if (array3 != null)
1251  {
1252  CopyToEntries(array3, index);
1253  }
1254  else
1255  {
1256  object[] array4 = array as object[];
1257  if (array4 == null)
1258  {
1259  throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayIncorrectType"), "array");
1260  }
1261  CopyToObjects(array4, index);
1262  }
1263  }
1264  }
1265  finally
1266  {
1267  ReleaseLocks(0, locksAcquired);
1268  }
1269  }
1270 
1271  private void GrowTable(Tables tables, IEqualityComparer<TKey> newComparer, bool regenerateHashKeys, int rehashCount)
1272  {
1273  int locksAcquired = 0;
1274  try
1275  {
1276  AcquireLocks(0, 1, ref locksAcquired);
1277  if (regenerateHashKeys && rehashCount == m_keyRehashCount)
1278  {
1279  tables = m_tables;
1280  goto IL_0099;
1281  }
1282  if (tables == m_tables)
1283  {
1284  long num = 0L;
1285  for (int i = 0; i < tables.m_countPerLock.Length; i++)
1286  {
1287  num += tables.m_countPerLock[i];
1288  }
1289  if (num >= tables.m_buckets.Length / 4)
1290  {
1291  goto IL_0099;
1292  }
1293  m_budget = 2 * m_budget;
1294  if (m_budget < 0)
1295  {
1296  m_budget = int.MaxValue;
1297  }
1298  }
1299  goto end_IL_0002;
1300  IL_0099:
1301  int j = 0;
1302  bool flag = false;
1303  try
1304  {
1305  for (j = checked(tables.m_buckets.Length * 2 + 1); j % 3 == 0 || j % 5 == 0 || j % 7 == 0; j = checked(j + 2))
1306  {
1307  }
1308  if (j > 2146435071)
1309  {
1310  flag = true;
1311  }
1312  }
1313  catch (OverflowException)
1314  {
1315  flag = true;
1316  }
1317  if (flag)
1318  {
1319  j = 2146435071;
1320  m_budget = int.MaxValue;
1321  }
1322  AcquireLocks(1, tables.m_locks.Length, ref locksAcquired);
1323  object[] array = tables.m_locks;
1324  if (m_growLockArray && tables.m_locks.Length < 1024)
1325  {
1326  array = new object[tables.m_locks.Length * 2];
1327  Array.Copy(tables.m_locks, array, tables.m_locks.Length);
1328  for (int k = tables.m_locks.Length; k < array.Length; k++)
1329  {
1330  array[k] = new object();
1331  }
1332  }
1333  Node[] array2 = new Node[j];
1334  int[] array3 = new int[array.Length];
1335  for (int l = 0; l < tables.m_buckets.Length; l++)
1336  {
1337  checked
1338  {
1339  Node next;
1340  for (Node node = tables.m_buckets[l]; node != null; node = next)
1341  {
1342  next = node.m_next;
1343  int hashcode = node.m_hashcode;
1344  if (regenerateHashKeys)
1345  {
1346  hashcode = newComparer.GetHashCode(node.m_key);
1347  }
1348  GetBucketAndLockNo(hashcode, out int bucketNo, out int lockNo, array2.Length, array.Length);
1349  array2[bucketNo] = new Node(node.m_key, node.m_value, hashcode, array2[bucketNo]);
1350  array3[lockNo]++;
1351  }
1352  }
1353  }
1354  if (regenerateHashKeys)
1355  {
1356  m_keyRehashCount++;
1357  }
1358  m_budget = Math.Max(1, array2.Length / array.Length);
1359  m_tables = new Tables(array2, array, array3, newComparer);
1360  end_IL_0002:;
1361  }
1362  finally
1363  {
1364  ReleaseLocks(0, locksAcquired);
1365  }
1366  }
1367 
1368  private void GetBucketAndLockNo(int hashcode, out int bucketNo, out int lockNo, int bucketCount, int lockCount)
1369  {
1370  bucketNo = (hashcode & int.MaxValue) % bucketCount;
1371  lockNo = bucketNo % lockCount;
1372  }
1373 
1374  private void AcquireAllLocks(ref int locksAcquired)
1375  {
1376  if (CDSCollectionETWBCLProvider.Log.IsEnabled())
1377  {
1378  CDSCollectionETWBCLProvider.Log.ConcurrentDictionary_AcquiringAllLocks(m_tables.m_buckets.Length);
1379  }
1380  AcquireLocks(0, 1, ref locksAcquired);
1381  AcquireLocks(1, m_tables.m_locks.Length, ref locksAcquired);
1382  }
1383 
1384  private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired)
1385  {
1386  object[] locks = m_tables.m_locks;
1387  for (int i = fromInclusive; i < toExclusive; i++)
1388  {
1389  bool lockTaken = false;
1390  try
1391  {
1392  Monitor.Enter(locks[i], ref lockTaken);
1393  }
1394  finally
1395  {
1396  if (lockTaken)
1397  {
1398  locksAcquired++;
1399  }
1400  }
1401  }
1402  }
1403 
1404  private void ReleaseLocks(int fromInclusive, int toExclusive)
1405  {
1406  for (int i = fromInclusive; i < toExclusive; i++)
1407  {
1408  Monitor.Exit(m_tables.m_locks[i]);
1409  }
1410  }
1411 
1412  private ReadOnlyCollection<TKey> GetKeys()
1413  {
1414  int locksAcquired = 0;
1415  try
1416  {
1417  AcquireAllLocks(ref locksAcquired);
1418  List<TKey> list = new List<TKey>();
1419  for (int i = 0; i < m_tables.m_buckets.Length; i++)
1420  {
1421  for (Node node = m_tables.m_buckets[i]; node != null; node = node.m_next)
1422  {
1423  list.Add(node.m_key);
1424  }
1425  }
1426  return new ReadOnlyCollection<TKey>(list);
1427  }
1428  finally
1429  {
1430  ReleaseLocks(0, locksAcquired);
1431  }
1432  }
1433 
1434  private ReadOnlyCollection<TValue> GetValues()
1435  {
1436  int locksAcquired = 0;
1437  try
1438  {
1439  AcquireAllLocks(ref locksAcquired);
1440  List<TValue> list = new List<TValue>();
1441  for (int i = 0; i < m_tables.m_buckets.Length; i++)
1442  {
1443  for (Node node = m_tables.m_buckets[i]; node != null; node = node.m_next)
1444  {
1445  list.Add(node.m_value);
1446  }
1447  }
1448  return new ReadOnlyCollection<TValue>(list);
1449  }
1450  finally
1451  {
1452  ReleaseLocks(0, locksAcquired);
1453  }
1454  }
1455 
1456  [Conditional("DEBUG")]
1457  private void Assert(bool condition)
1458  {
1459  }
1460 
1461  private string GetResource(string key)
1462  {
1463  return Environment.GetResourceString(key);
1464  }
1465 
1466  [OnSerializing]
1467  private void OnSerializing(StreamingContext context)
1468  {
1469  Tables tables = m_tables;
1470  m_serializationArray = ToArray();
1471  m_serializationConcurrencyLevel = tables.m_locks.Length;
1472  m_serializationCapacity = tables.m_buckets.Length;
1473  m_comparer = (IEqualityComparer<TKey>)HashHelpers.GetEqualityComparerForSerialization(tables.m_comparer);
1474  }
1475 
1476  [OnDeserialized]
1477  private void OnDeserialized(StreamingContext context)
1478  {
1479  KeyValuePair<TKey, TValue>[] serializationArray = m_serializationArray;
1480  Node[] buckets = new Node[m_serializationCapacity];
1481  int[] countPerLock = new int[m_serializationConcurrencyLevel];
1482  object[] array = new object[m_serializationConcurrencyLevel];
1483  for (int i = 0; i < array.Length; i++)
1484  {
1485  array[i] = new object();
1486  }
1487  m_tables = new Tables(buckets, array, countPerLock, m_comparer);
1488  InitializeFromCollection(serializationArray);
1489  m_serializationArray = null;
1490  }
1491  }
1492 }
The exception that is thrown when a null reference (Nothing in Visual Basic) is passed to a method th...
Provides a base class for implementations of the T:System.Collections.Generic.IEqualityComparer`1 gen...
TValue Value
Gets the value in the key/value pair.
Definition: KeyValuePair.cs:32
static void Write(ref bool location, bool value)
Writes the specified value to the specified field. On systems that require it, inserts a memory barri...
Definition: Volatile.cs:186
void Reset()
Sets the enumerator to its initial position, which is before the first element in the collection.
bool MoveNext()
Advances the enumerator to the next element of the collection.
Provides the base class for a generic read-only collection.
bool TryAdd(TKey key, TValue value)
Attempts to add the specified key and value to the T:System.Collections.Concurrent....
Represents a thread-safe collection of key/value pairs that can be accessed by multiple threads concu...
ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer< TKey > comparer)
Initializes a new instance of the T:System.Collections.Concurrent.ConcurrentDictionary`2 class that i...
ICollection< TKey > Keys
Gets an T:System.Collections.Generic.ICollection`1 containing the keys of the T:System....
Definition: IDictionary.cs:29
Definition: __Canon.cs:3
new IEnumerator< T > GetEnumerator()
Returns an enumerator that iterates through the collection.
The exception that is thrown when the value of an argument is outside the allowable range of values a...
Provides a mechanism that synchronizes access to objects.
Definition: Monitor.cs:13
bool TryRemove(TKey key, out TValue value)
Attempts to remove and return the value that has the specified key from the T:System....
bool Remove(T item)
Removes the first occurrence of a specific object from the T:System.Collections.Generic....
Exposes the enumerator, which supports a simple iteration over a collection of a specified type....
Definition: IEnumerable.cs:9
Represents a strongly-typed, read-only collection of elements.
ConcurrentDictionary()
Initializes a new instance of the T:System.Collections.Concurrent.ConcurrentDictionary`2 class that i...
void CopyTo(T[] array, int arrayIndex)
Copies the elements of the T:System.Collections.Generic.ICollection`1 to an T:System....
Describes the source and destination of a given serialized stream, and provides an additional caller-...
bool TryGetValue(TKey key, out TValue value)
Attempts to get the value associated with the specified key from the T:System.Collections....
ICollection< TValue > Values
Gets an T:System.Collections.Generic.ICollection`1 containing the values in the T:System....
Definition: IDictionary.cs:38
TValue AddOrUpdate(TKey key, TValue addValue, Func< TKey, TValue, TValue > updateValueFactory)
Adds a key/value pair to the T:System.Collections.Concurrent.ConcurrentDictionary`2 if the key does n...
static EqualityComparer< T > Default
Returns a default equality comparer for the type specified by the generic argument.
Supports a simple iteration over a generic collection.
Definition: IEnumerator.cs:6
IEnumerable< TValue > Values
Gets an enumerable collection that contains the values in the read-only dictionary.
The exception that is thrown when the key specified for accessing an element in a collection does not...
Defines a key/value pair that can be set or retrieved.
Definition: KeyValuePair.cs:10
Exposes an enumerator, which supports a simple iteration over a non-generic collection....
Definition: IEnumerable.cs:9
SecurityAction
Specifies the security actions that can be performed using declarative security.
static void Enter(object obj)
Acquires an exclusive lock on the specified object.
TKey Key
Gets the key in the key/value pair.
Definition: KeyValuePair.cs:20
new bool Equals(object x, object y)
Determines whether the specified objects are equal.
TValue GetOrAdd(TKey key, TValue value)
Adds a key/value pair to the T:System.Collections.Concurrent.ConcurrentDictionary`2 if the key does n...
ICollection< TKey > Keys
Gets a collection containing the keys in the T:System.Collections.Generic.Dictionary`2.
Represents a generic collection of key/value pairs.
Definition: IDictionary.cs:7
ConcurrentDictionary(IEqualityComparer< TKey > comparer)
Initializes a new instance of the T:System.Collections.Concurrent.ConcurrentDictionary`2 class that i...
TValue GetOrAdd(TKey key, Func< TKey, TValue > valueFactory)
Adds a key/value pair to the T:System.Collections.Concurrent.ConcurrentDictionary`2 by using the spec...
bool Contains(T item)
Determines whether the T:System.Collections.Generic.ICollection`1 contains a specific value.
int Count
Gets the number of key/value pairs contained in the T:System.Collections.Concurrent....
void Add(object key, object value)
Adds an element with the provided key and value to the T:System.Collections.IDictionary object.
ICollection< TValue > Values
Gets a collection that contains the values in the T:System.Collections.Generic.Dictionary`2.
static sbyte Max(sbyte val1, sbyte val2)
Returns the larger of two 8-bit signed integers.
Definition: Math.cs:581
bool IsReadOnly
Gets a value indicating whether the T:System.Collections.Generic.ICollection`1 is read-only.
Definition: ICollection.cs:25
bool Remove(TKey key)
Removes the element with the specified key from the T:System.Collections.Generic.IDictionary`2.
bool ContainsKey(TKey key)
Determines whether the T:System.Collections.Concurrent.ConcurrentDictionary`2 contains the specified ...
ConcurrentDictionary(int concurrencyLevel, int capacity)
Initializes a new instance of the T:System.Collections.Concurrent.ConcurrentDictionary`2 class that i...
object Current
Gets the element in the collection at the current position of the enumerator.
Definition: IEnumerator.cs:15
static void Exit(object obj)
Releases an exclusive lock on the specified object.
Contains methods for performing volatile memory operations.
Definition: Volatile.cs:8
int GetHashCode(T obj)
Returns a hash code for the specified object.
IEnumerator< KeyValuePair< TKey, TValue > > GetEnumerator()
Returns an enumerator that iterates through the T:System.Collections.Concurrent.ConcurrentDictionary`...
Represents a generic read-only collection of key/value pairs.
static bool Read(ref bool location)
Reads the value of the specified field. On systems that require it, inserts a memory barrier that pre...
Definition: Volatile.cs:15
TValue AddOrUpdate(TKey key, Func< TKey, TValue > addValueFactory, Func< TKey, TValue, TValue > updateValueFactory)
Uses the specified functions to add a key/value pair to the T:System.Collections.Concurrent....
int GetHashCode(object obj)
Returns a hash code for the specified object.
The exception that is thrown when one of the arguments provided to a method is not valid.
KeyValuePair< TKey, TValue > [] ToArray()
Copies the key and value pairs stored in the T:System.Collections.Concurrent.ConcurrentDictionary`2 t...
Represents a strongly typed list of objects that can be accessed by index. Provides methods to search...
Definition: List.cs:14
ConcurrentDictionary(IEnumerable< KeyValuePair< TKey, TValue >> collection, IEqualityComparer< TKey > comparer)
Initializes a new instance of the T:System.Collections.Concurrent.ConcurrentDictionary`2 class that c...
Specifies that the class can be serialized.
void Add(TKey key, TValue value)
Adds an element with the provided key and value to the T:System.Collections.Generic....
Enumerates the elements of a nongeneric dictionary.
This value supports the .NET Framework infrastructure and is not intended to be used directly from yo...
Provides constants and static methods for trigonometric, logarithmic, and other common mathematical f...
Definition: Math.cs:10
Defines size, enumerators, and synchronization methods for all nongeneric collections.
Definition: ICollection.cs:8
A conditional operation, such as a > b ? a : b in C# or If(a > b, a, b) in Visual Basic.
void CopyTo(Array array, int index)
Copies the elements of the T:System.Collections.ICollection to an T:System.Array, starting at a parti...
Defines a dictionary key/value pair that can be set or retrieved.
void Clear()
Removes all keys and values from the T:System.Collections.Concurrent.ConcurrentDictionary`2.
Represents a nongeneric collection of key/value pairs.
Definition: IDictionary.cs:8
bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue)
Compares the existing value for the specified key with a specified value, and if they are equal,...
IEnumerable< TKey > Keys
Gets an enumerable collection that contains the keys in the read-only dictionary.
The default setting for this enumeration, which is currently F:System.GCCollectionMode....
Supports a simple iteration over a non-generic collection.
Definition: IEnumerator.cs:9
void Add(T item)
Adds an item to the T:System.Collections.Generic.ICollection`1.
ConcurrentDictionary(int concurrencyLevel, IEnumerable< KeyValuePair< TKey, TValue >> collection, IEqualityComparer< TKey > comparer)
Initializes a new instance of the T:System.Collections.Concurrent.ConcurrentDictionary`2 class that c...
ConcurrentDictionary(IEnumerable< KeyValuePair< TKey, TValue >> collection)
Initializes a new instance of the T:System.Collections.Concurrent.ConcurrentDictionary`2 class that c...
bool IsEmpty
Gets a value that indicates whether the T:System.Collections.Concurrent.ConcurrentDictionary`2 is emp...