• C#ConcurrentDictionary源代码


    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Collections;
    using System.Runtime.Serialization;
    using System.Security;
    using System.Security.Permissions;
    using System.Collections.ObjectModel;
     
    #if !CDS_COMPILE_JUST_THIS
    using System.Diagnostics.Contracts;
    #endif
     
    namespace System.Collections.Concurrent
    {
     
        /// <summary>
        /// Represents a thread-safe collection of keys and values.
        /// </summary>
        /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
        /// <remarks>
        /// All public and protected members of <see cref="ConcurrentDictionary{TKey,TValue}"> are thread-safe and may be used
        /// concurrently from multiple threads.
        /// </see></remarks>
        [Serializable]
        [ComVisible(false)]
        [DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))]
        [DebuggerDisplay("Count = {Count}")]
        [HostProtection(Synchronization = true, ExternalThreading = true)]
        public class ConcurrentDictionary<tkey, tvalue=""> : IDictionary<tkey, tvalue="">, IDictionary
        {
            [NonSerialized]
            private volatile Node[] m_buckets; // A singly-linked list for each bucket.
            [NonSerialized]
            private object[] m_locks; // A set of locks, each guarding a section of the table.
            [NonSerialized]
            private volatile int[] m_countPerLock; // The number of elements guarded by each lock.
            private IEqualityComparer<tkey> m_comparer; // Key equality comparer
     
            private KeyValuePair<tkey, tvalue="">[] m_serializationArray; // Used for custom serialization
     
            private int m_serializationConcurrencyLevel; // used to save the concurrency level in serialization
     
            private int m_serializationCapacity; // used to save the capacity in serialization
     
            // The default concurrency level is DEFAULT_CONCURRENCY_MULTIPLIER * #CPUs. The higher the
            // DEFAULT_CONCURRENCY_MULTIPLIER, the more concurrent writes can take place without interference
            // and blocking, but also the more expensive operations that require all locks become (e.g. table
            // resizing, ToArray, Count, etc). According to brief benchmarks that we ran, 4 seems like a good
            // compromise.
            private const int DEFAULT_CONCURRENCY_MULTIPLIER = 4;
     
            // The default capacity, i.e. the initial # of buckets. When choosing this value, we are making
            // a trade-off between the size of a very small dictionary, and the number of resizes when
            // constructing a large dictionary. Also, the capacity should not be divisible by a small prime.
            private const int DEFAULT_CAPACITY = 31;
     
            /// <summary>
            /// Initializes a new instance of the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// class that is empty, has the default concurrency level, has the default initial capacity, and
            /// uses the default comparer for the key type.
            /// </see></summary>
            public ConcurrentDictionary() : this(DefaultConcurrencyLevel, DEFAULT_CAPACITY) { }
     
            /// <summary>
            /// Initializes a new instance of the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// class that is empty, has the specified concurrency level and capacity, and uses the default
            /// comparer for the key type.
            /// </see></summary>
            /// <param name="concurrencyLevel">The estimated number of threads that will update the
            /// <see cref="ConcurrentDictionary{TKey,TValue}"> concurrently.
            /// <param name="capacity">The initial number of elements that the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// can contain.
            /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="concurrencyLevel"> is
            /// less than 1.</paramref></exception>
            /// <exception cref="T:System.ArgumentOutOfRangeException"> <paramref name="capacity"> is less than
            /// 0.</paramref></exception>
            public ConcurrentDictionary(int concurrencyLevel, int capacity) : this(concurrencyLevel, capacity, EqualityComparer<tkey>.Default) { }
     
            /// <summary>
            /// Initializes a new instance of the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// class that contains elements copied from the specified <see cref="T:System.Collections.IEnumerable{KeyValuePair{TKey,TValue}}">, has the default concurrency
            /// level, has the default initial capacity, and uses the default comparer for the key type.
            /// </see></see></summary>
            /// <param name="collection">The <see cref="T:System.Collections.IEnumerable{KeyValuePair{TKey,TValue}}"> whose elements are copied to
            /// the new
            /// <see cref="ConcurrentDictionary{TKey,TValue}">.
            /// <exception cref="T:System.ArgumentNullException"><paramref name="collection"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.ArgumentException"><paramref name="collection"> contains one or more
            /// duplicate keys.</paramref></exception>
            public ConcurrentDictionary(IEnumerable<keyvaluepair<tkey, tvalue="">> collection) : this(collection, EqualityComparer<tkey>.Default) { }
     
            /// <summary>
            /// Initializes a new instance of the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// class that is empty, has the specified concurrency level and capacity, and uses the specified
            /// <see cref="T:System.Collections.Generic.IEqualityComparer{TKey}">.
            /// </see></see></summary>
            /// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer{TKey}">
            /// implementation to use when comparing keys.
            /// <exception cref="T:System.ArgumentNullException"><paramref name="comparer"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            public ConcurrentDictionary(IEqualityComparer<tkey> comparer) : this(DefaultConcurrencyLevel, DEFAULT_CAPACITY, comparer) { }
     
            /// <summary>
            /// Initializes a new instance of the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// class that contains elements copied from the specified <see cref="T:System.Collections.IEnumerable">, has the default concurrency level, has the default
            /// initial capacity, and uses the specified
            /// <see cref="T:System.Collections.Generic.IEqualityComparer{TKey}">.
            /// </see></see></see></summary>
            /// <param name="collection">The <see cref="T:System.Collections.IEnumerable{KeyValuePair{TKey,TValue}}"> whose elements are copied to
            /// the new
            /// <see cref="ConcurrentDictionary{TKey,TValue}">.
            /// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer{TKey}">
            /// implementation to use when comparing keys.
            /// <exception cref="T:System.ArgumentNullException"><paramref name="collection"> is a null reference
            /// (Nothing in Visual Basic). -or-
            /// <paramref name="comparer"> is a null reference (Nothing in Visual Basic).
            /// </paramref></paramref></exception>
            public ConcurrentDictionary(IEnumerable<keyvaluepair<tkey, tvalue="">> collection, IEqualityComparer<tkey> comparer)
                : this(DefaultConcurrencyLevel, collection, comparer) { }
     
            /// <summary>
            /// Initializes a new instance of the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// class that contains elements copied from the specified <see cref="T:System.Collections.IEnumerable">,
            /// has the specified concurrency level, has the specified initial capacity, and uses the specified
            /// <see cref="T:System.Collections.Generic.IEqualityComparer{TKey}">.
            /// </see></see></see></summary>
            /// <param name="concurrencyLevel">The estimated number of threads that will update the
            /// <see cref="ConcurrentDictionary{TKey,TValue}"> concurrently.
            /// <param name="collection">The <see cref="T:System.Collections.IEnumerable{KeyValuePair{TKey,TValue}}"> whose elements are copied to the new
            /// <see cref="ConcurrentDictionary{TKey,TValue}">.
            /// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer{TKey}"> implementation to use
            /// when comparing keys.
            /// <exception cref="T:System.ArgumentNullException">
            /// <paramref name="collection"> is a null reference (Nothing in Visual Basic).
            /// -or-
            /// <paramref name="comparer"> is a null reference (Nothing in Visual Basic).
            /// </paramref></paramref></exception>
            /// <exception cref="T:System.ArgumentOutOfRangeException">
            /// <paramref name="concurrencyLevel"> is less than 1.
            /// </paramref></exception>
            /// <exception cref="T:System.ArgumentException"><paramref name="collection"> contains one or more duplicate keys.</paramref></exception>
            public ConcurrentDictionary(
                int concurrencyLevel, IEnumerable<keyvaluepair<tkey, tvalue="">> collection, IEqualityComparer<tkey> comparer)
                : this(concurrencyLevel, DEFAULT_CAPACITY, comparer)
            {
                if (collection == null) throw new ArgumentNullException("collection");
                if (comparer == null) throw new ArgumentNullException("comparer");
     
                InitializeFromCollection(collection);
            }
     
            private void InitializeFromCollection(IEnumerable<keyvaluepair<tkey, tvalue="">> collection)
            {
                TValue dummy;
                foreach (KeyValuePair<tkey, tvalue=""> pair in collection)
                {
                    if (pair.Key == null) throw new ArgumentNullException("key");
     
                    if (!TryAddInternal(pair.Key, pair.Value, false, false, out dummy))
                    {
                        throw new ArgumentException(GetResource("ConcurrentDictionary_SourceContainsDuplicateKeys"));
                    }
                }
            }
     
            /// <summary>
            /// Initializes a new instance of the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// class that is empty, has the specified concurrency level, has the specified initial capacity, and
            /// uses the specified <see cref="T:System.Collections.Generic.IEqualityComparer{TKey}">.
            /// </see></see></summary>
            /// <param name="concurrencyLevel">The estimated number of threads that will update the
            /// <see cref="ConcurrentDictionary{TKey,TValue}"> concurrently.
            /// <param name="capacity">The initial number of elements that the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// can contain.
            /// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer{TKey}">
            /// implementation to use when comparing keys.
            /// <exception cref="T:System.ArgumentOutOfRangeException">
            /// <paramref name="concurrencyLevel"> is less than 1. -or-
            /// <paramref name="capacity"> is less than 0.
            /// </paramref></paramref></exception>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="comparer"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<tkey> comparer)
            {
                if (concurrencyLevel < 1)
                {
                    throw new ArgumentOutOfRangeException("concurrencyLevel", GetResource("ConcurrentDictionary_ConcurrencyLevelMustBePositive"));
                }
                if (capacity < 0)
                {
                    throw new ArgumentOutOfRangeException("capacity", GetResource("ConcurrentDictionary_CapacityMustNotBeNegative"));
                }
                if (comparer == null) throw new ArgumentNullException("comparer");
     
                // The capacity should be at least as large as the concurrency level. Otherwise, we would have locks that don't guard
                // any buckets.
                if (capacity < concurrencyLevel)
                {
                    capacity = concurrencyLevel;
                }
     
                m_locks = new object[concurrencyLevel];
                for (int i = 0; i < m_locks.Length; i++)
                {
                    m_locks[i] = new object();
                }
     
                m_countPerLock = new int[m_locks.Length];
                m_buckets = new Node[capacity];
                m_comparer = comparer;
            }
     
     
            /// <summary>
            /// Attempts to add the specified key and value to the <see cref="ConcurrentDictionary{TKey,
            /// TValue}">.
            /// </see></summary>
            /// <param name="key">The key of the element to add.
            /// <param name="value">The value of the element to add. The value can be a null reference (Nothing
            /// in Visual Basic) for reference types.
            /// <returns>true if the key/value pair was added to the <see cref="ConcurrentDictionary{TKey,
            /// TValue}">
            /// successfully; otherwise, false.</see></returns>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.OverflowException">The <see cref="ConcurrentDictionary{TKey, TValue}">
            /// contains too many elements.</see></exception>
            public bool TryAdd(TKey key, TValue value)
            {
                if (key == null) throw new ArgumentNullException("key");
                TValue dummy;
                return TryAddInternal(key, value, false, true, out dummy);
            }
     
            /// <summary>
            /// Determines whether the <see cref="ConcurrentDictionary{TKey, TValue}"> contains the specified
            /// key.
            /// </see></summary>
            /// <param name="key">The key to locate in the <see cref="ConcurrentDictionary{TKey,
            /// TValue}">.
            /// <returns>true if the <see cref="ConcurrentDictionary{TKey, TValue}"> contains an element with
            /// the specified key; otherwise, false.</see></returns>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            public bool ContainsKey(TKey key)
            {
                if (key == null) throw new ArgumentNullException("key");
     
                TValue throwAwayValue;
                return TryGetValue(key, out throwAwayValue);
            }
     
            /// <summary>
            /// Attempts to remove and return the the value with the specified key from the
            /// <see cref="ConcurrentDictionary{TKey, TValue}">.
            /// </see></summary>
            /// <param name="key">The key of the element to remove and return.
            /// <param name="value">When this method returns, <paramref name="value"> contains the object removed from the
            /// <see cref="ConcurrentDictionary{TKey,TValue}"> or the default value of <typeparamref name="TValue">
            /// if the operation failed.
            /// <returns>true if an object was removed successfully; otherwise, false.</returns>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            public bool TryRemove(TKey key, out TValue value)
            {
                if (key == null) throw new ArgumentNullException("key");
     
                return TryRemoveInternal(key, out value, false, default(TValue));
            }
     
            /// <summary>
            /// Removes the specified key from the dictionary if it exists and returns its associated value.
            /// If matchValue flag is set, the key will be removed only if is associated with a particular
            /// value.
            /// </summary>
            /// <param name="key">The key to search for and remove if it exists.
            /// <param name="value">The variable into which the removed value, if found, is stored.
            /// <param name="matchValue">Whether removal of the key is conditional on its value.
            /// <param name="oldValue">The conditional value to compare against if <paramref name="matchValue"> is true
            /// <returns></returns>
            private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue)
            {
                while (true)
                {
                    Node[] buckets = m_buckets;
     
                    int bucketNo, lockNo;
                    GetBucketAndLockNo(m_comparer.GetHashCode(key), out bucketNo, out lockNo, buckets.Length);
     
                    lock (m_locks[lockNo])
                    {
                        // If the table just got resized, we may not be holding the right lock, and must retry.
                        // This should be a rare occurence.
                        if (buckets != m_buckets)
                        {
                            continue;
                        }
     
                        Node prev = null;
                        for (Node curr = m_buckets[bucketNo]; curr != null; curr = curr.m_next)
                        {
                            Assert((prev == null && curr == m_buckets[bucketNo]) || prev.m_next == curr);
     
                            if (m_comparer.Equals(curr.m_key, key))
                            {
                                if (matchValue)
                                {
                                    bool valuesMatch = EqualityComparer<tvalue>.Default.Equals(oldValue, curr.m_value);
                                    if (!valuesMatch)
                                    {
                                        value = default(TValue);
                                        return false;
                                    }
                                }
     
                                if (prev == null)
                                {
                                    m_buckets[bucketNo] = curr.m_next;
                                }
                                else
                                {
                                    prev.m_next = curr.m_next;
                                }
     
                                value = curr.m_value;
                                m_countPerLock[lockNo]--;
                                return true;
                            }
                            prev = curr;
                        }
                    }
     
                    value = default(TValue);
                    return false;
                }
            }
     
            /// <summary>
            /// Attempts to get the value associated with the specified key from the <see cref="ConcurrentDictionary{TKey,TValue}">.
            /// </see></summary>
            /// <param name="key">The key of the value to get.
            /// <param name="value">When this method returns, <paramref name="value"> contains the object from
            /// the
            /// <see cref="ConcurrentDictionary{TKey,TValue}"> with the spedified key or the default value of
            /// <typeparamref name="TValue">, if the operation failed.
            /// <returns>true if the key was found in the <see cref="ConcurrentDictionary{TKey,TValue}">;
            /// otherwise, false.</see></returns>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            public bool TryGetValue(TKey key, out TValue value)
            {
                if (key == null) throw new ArgumentNullException("key");
     
                int bucketNo, lockNoUnused;
     
                // We must capture the m_buckets field in a local variable. It is set to a new table on each table resize.
                Node[] buckets = m_buckets;
                GetBucketAndLockNo(m_comparer.GetHashCode(key), out bucketNo, out lockNoUnused, buckets.Length);
     
                // We can get away w/out a lock here.
                Node n = buckets[bucketNo];
     
                // The memory barrier ensures that the load of the fields of 'n' doesn’t move before the load from buckets[i].
                Thread.MemoryBarrier();
                while (n != null)
                {
                    if (m_comparer.Equals(n.m_key, key))
                    {
                        value = n.m_value;
                        return true;
                    }
                    n = n.m_next;
                }
     
                value = default(TValue);
                return false;
            }
     
            /// <summary>
            /// Compares the existing value for the specified key with a specified value, and if they’re equal,
            /// updates the key with a third value.
            /// </summary>
            /// <param name="key">The key whose value is compared with <paramref name="comparisonValue"> and
            /// possibly replaced.
            /// <param name="newValue">The value that replaces the value of the element with <paramref name="key"> if the comparison results in equality.
            /// <param name="comparisonValue">The value that is compared to the value of the element with
            /// <paramref name="key">.
            /// <returns>true if the value with <paramref name="key"> was equal to <paramref name="comparisonValue"> and replaced with <paramref name="newValue">; otherwise,
            /// false.</paramref></paramref></paramref></returns>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null
            /// reference.</paramref></exception>
            public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue)
            {
                if (key == null) throw new ArgumentNullException("key");
     
                int hashcode = m_comparer.GetHashCode(key);
                IEqualityComparer<tvalue> valueComparer = EqualityComparer<tvalue>.Default;
     
                while (true)
                {
                    int bucketNo;
                    int lockNo;
     
                    Node[] buckets = m_buckets;
                    GetBucketAndLockNo(hashcode, out bucketNo, out lockNo, buckets.Length);
     
                    lock (m_locks[lockNo])
                    {
                        // If the table just got resized, we may not be holding the right lock, and must retry.
                        // This should be a rare occurence.
                        if (buckets != m_buckets)
                        {
                            continue;
                        }
     
                        // Try to find this key in the bucket
                        Node prev = null;
                        for (Node node = buckets[bucketNo]; node != null; node = node.m_next)
                        {
                            Assert((prev == null && node == m_buckets[bucketNo]) || prev.m_next == node);
                            if (m_comparer.Equals(node.m_key, key))
                            {
                                if (valueComparer.Equals(node.m_value, comparisonValue))
                                {
                                    // Replace the old node with a new node. Unfortunately, we cannot simply
                                    // change node.m_value in place. We don't know the size of TValue, so
                                    // its writes may not be atomic.
                                    Node newNode = new Node(node.m_key, newValue, hashcode, node.m_next);
     
                                    if (prev == null)
                                    {
                                        buckets[bucketNo] = newNode;
                                    }
                                    else
                                    {
                                        prev.m_next = newNode;
                                    }
     
                                    return true;
                                }
     
                                return false;
                            }
     
                            prev = node;
                        }
     
                        //didn't find the key
                        return false;
                    }
                }
            }
     
            /// <summary>
            /// Removes all keys and values from the <see cref="ConcurrentDictionary{TKey,TValue}">.
            /// </see></summary>
            public void Clear()
            {
                int locksAcquired = 0;
                try
                {
                    AcquireAllLocks(ref locksAcquired);
     
                    m_buckets = new Node[DEFAULT_CAPACITY];
                    Array.Clear(m_countPerLock, 0, m_countPerLock.Length);
                }
                finally
                {
                    ReleaseLocks(0, locksAcquired);
                }
            }
     
            /// <summary>
            /// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection"> to an array of
            /// type <see cref="T:System.Collections.Generic.KeyValuePair{TKey,TValue}">, starting at the
            /// specified array index.
            /// </see></see></summary>
            /// <param name="array">The one-dimensional array of type <see cref="T:System.Collections.Generic.KeyValuePair{TKey,TValue}">
            /// that is the destination of the <see cref="T:System.Collections.Generic.KeyValuePair{TKey,TValue}"> elements copied from the <see cref="T:System.Collections.ICollection">. The array must have zero-based indexing.
            /// <param name="index">The zero-based index in <paramref name="array"> at which copying
            /// begins.
            /// <exception cref="T:System.ArgumentNullException"><paramref name="array"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"> is less than
            /// 0.</paramref></exception>
            /// <exception cref="T:System.ArgumentException"><paramref name="index"> is equal to or greater than
            /// the length of the <paramref name="array">. -or- The number of elements in the source <see cref="T:System.Collections.ICollection">
            /// is greater than the available space from <paramref name="index"> to the end of the destination
            /// <paramref name="array">.</paramref></paramref></see></paramref></paramref></exception>
            void ICollection<keyvaluepair<tkey, tvalue="">>.CopyTo(KeyValuePair<tkey, tvalue="">[] array, int index)
            {
                if (array == null) throw new ArgumentNullException("array");
                if (index < 0) throw new ArgumentOutOfRangeException("index", GetResource("ConcurrentDictionary_IndexIsNegative"));
     
                int locksAcquired = 0;
                try
                {
                    AcquireAllLocks(ref locksAcquired);
     
                    int count = 0;
     
                    for (int i = 0; i < m_locks.Length; i++)
                    {
                        count += m_countPerLock[i];
                    }
     
                    if (array.Length - count < index || count < 0) //"count" itself or "count + index" can overflow
                    {
                        throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayNotLargeEnough"));
                    }
     
                    CopyToPairs(array, index);
                }
                finally
                {
                    ReleaseLocks(0, locksAcquired);
                }
            }
     
            /// <summary>
            /// Copies the key and value pairs stored in the <see cref="ConcurrentDictionary{TKey,TValue}"> to a
            /// new array.
            /// </see></summary>
            /// <returns>A new array containing a snapshot of key and value pairs copied from the <see cref="ConcurrentDictionary{TKey,TValue}">.</see></returns>
            public KeyValuePair<tkey, tvalue="">[] ToArray()
            {
                int locksAcquired = 0;
                try
                {
                    AcquireAllLocks(ref locksAcquired);
                    int count = 0;
                    checked
                    {
                        for (int i = 0; i < m_locks.Length; i++)
                        {
                            count += m_countPerLock[i];
                        }
                    }
     
                    KeyValuePair<tkey, tvalue="">[] array = new KeyValuePair<tkey, tvalue="">[count];
     
                    CopyToPairs(array, 0);
                    return array;
                }
                finally
                {
                    ReleaseLocks(0, locksAcquired);
                }
            }
     
            /// <summary>
            /// Copy dictionary contents to an array - shared implementation between ToArray and CopyTo.
            ///
            /// Important: the caller must hold all locks in m_locks before calling CopyToPairs.
            /// </summary>
            private void CopyToPairs(KeyValuePair<tkey, tvalue="">[] array, int index)
            {
                Node[] buckets = m_buckets;
                for (int i = 0; i < buckets.Length; i++)
                {
                    for (Node current = buckets[i]; current != null; current = current.m_next)
                    {
                        array[index] = new KeyValuePair<tkey, tvalue="">(current.m_key, current.m_value);
                        index++; //this should never flow, CopyToPairs is only called when there's no overflow risk
                    }
                }
            }
     
            /// <summary>
            /// Copy dictionary contents to an array - shared implementation between ToArray and CopyTo.
            ///
            /// Important: the caller must hold all locks in m_locks before calling CopyToEntries.
            /// </summary>
            private void CopyToEntries(DictionaryEntry[] array, int index)
            {
                Node[] buckets = m_buckets;
                for (int i = 0; i < buckets.Length; i++)
                {
                    for (Node current = buckets[i]; current != null; current = current.m_next)
                    {
                        array[index] = new DictionaryEntry(current.m_key, current.m_value);
                        index++;  //this should never flow, CopyToEntries is only called when there's no overflow risk
                    }
                }
            }
     
            /// <summary>
            /// Copy dictionary contents to an array - shared implementation between ToArray and CopyTo.
            ///
            /// Important: the caller must hold all locks in m_locks before calling CopyToObjects.
            /// </summary>
            private void CopyToObjects(object[] array, int index)
            {
                Node[] buckets = m_buckets;
                for (int i = 0; i < buckets.Length; i++)
                {
                    for (Node current = buckets[i]; current != null; current = current.m_next)
                    {
                        array[index] = new KeyValuePair<tkey, tvalue="">(current.m_key, current.m_value);
                        index++; //this should never flow, CopyToObjects is only called when there's no overflow risk
                    }
                }
            }
     
            /// <summary>Returns an enumerator that iterates through the <see cref="ConcurrentDictionary{TKey,TValue}">.</see></summary>
            /// <returns>An enumerator for the <see cref="ConcurrentDictionary{TKey,TValue}">.</see></returns>
            /// <remarks>
            /// The enumerator returned from the dictionary is safe to use concurrently with
            /// reads and writes to the dictionary, however it does not represent a moment-in-time snapshot
            /// of the dictionary.  The contents exposed through the enumerator may contain modifications
            /// made to the dictionary after <see cref="GetEnumerator"> was called.
            /// </see></remarks>
            public IEnumerator<keyvaluepair<tkey, tvalue="">> GetEnumerator()
            {
                Node[] buckets = m_buckets;
     
                for (int i = 0; i < buckets.Length; i++)
                {
                    Node current = buckets[i];
     
                    // The memory barrier ensures that the load of the fields of 'current' doesn’t move before the load from buckets[i].
                    Thread.MemoryBarrier();
                    while (current != null)
                    {
                        yield return new KeyValuePair<tkey, tvalue="">(current.m_key, current.m_value);
                        current = current.m_next;
                    }
                }
            }
     
            /// <summary>
            /// Shared internal implementation for inserts and updates.
            /// If key exists, we always return false; and if updateIfExists == true we force update with value;
            /// If key doesn't exist, we always add value and return true;
            /// </summary>
            private bool TryAddInternal(TKey key, TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue)
            {
                int hashcode = m_comparer.GetHashCode(key);
     
                while (true)
                {
                    int bucketNo, lockNo;
     
                    Node[] buckets = m_buckets;
                    GetBucketAndLockNo(hashcode, out bucketNo, out lockNo, buckets.Length);
     
                    bool resizeDesired = false;
                    bool lockTaken = false;
                    try
                    {
                        if (acquireLock)
                            Monitor.Enter(m_locks[lockNo], ref lockTaken);
     
                        // If the table just got resized, we may not be holding the right lock, and must retry.
                        // This should be a rare occurence.
                        if (buckets != m_buckets)
                        {
                            continue;
                        }
     
                        // Try to find this key in the bucket
                        Node prev = null;
                        for (Node node = buckets[bucketNo]; node != null; node = node.m_next)
                        {
                            Assert((prev == null && node == m_buckets[bucketNo]) || prev.m_next == node);
                            if (m_comparer.Equals(node.m_key, key))
                            {
                                // The key was found in the dictionary. If updates are allowed, update the value for that key.
                                // We need to create a new node for the update, in order to support TValue types that cannot
                                // be written atomically, since lock-free reads may be happening concurrently.
                                if (updateIfExists)
                                {
                                    Node newNode = new Node(node.m_key, value, hashcode, node.m_next);
                                    if (prev == null)
                                    {
                                        buckets[bucketNo] = newNode;
                                    }
                                    else
                                    {
                                        prev.m_next = newNode;
                                    }
                                    resultingValue = value;
                                }
                                else
                                {
                                    resultingValue = node.m_value;
                                }
                                return false;
                            }
                            prev = node;
                        }
     
                        // The key was not found in the bucket. Insert the key-value pair.
                        buckets[bucketNo] = new Node(key, value, hashcode, buckets[bucketNo]);
                        checked
                        {
                            m_countPerLock[lockNo]++;
                        }
     
                        //
                        // If this lock has element / bucket ratio greater than 1, resize the entire table.
                        // Note: the formula is chosen to avoid overflow, but has a small inaccuracy due to
                        // rounding.
                        //
                        if (m_countPerLock[lockNo] > buckets.Length / m_locks.Length)
                        {
                            resizeDesired = true;
                        }
                    }
                    finally
                    {
                        if (lockTaken)
                            Monitor.Exit(m_locks[lockNo]);
                    }
     
                    //
                    // The fact that we got here means that we just performed an insertion. If necessary, we will grow the table.
                    //
                    // Concurrency notes:
                    // - Notice that we are not holding any locks at when calling GrowTable. This is necessary to prevent deadlocks.
                    // - As a result, it is possible that GrowTable will be called unnecessarily. But, GrowTable will obtain lock 0
                    //   and then verify that the table we passed to it as the argument is still the current table.
                    //
                    if (resizeDesired)
                    {
                        GrowTable(buckets);
                    }
     
                    resultingValue = value;
                    return true;
                }
            }
     
            /// <summary>
            /// Gets or sets the value associated with the specified key.
            /// </summary>
            /// <param name="key">The key of the value to get or set.
            /// <value>The value associated with the specified key. If the specified key is not found, a get
            /// operation throws a
            /// <see cref="T:Sytem.Collections.Generic.KeyNotFoundException">, and a set operation creates a new
            /// element with the specified key.</see></value>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.Collections.Generic.KeyNotFoundException">The property is retrieved and
            /// <paramref name="key">
            /// does not exist in the collection.</paramref></exception>
            public TValue this[TKey key]
            {
                get
                {
                    TValue value;
                    if (!TryGetValue(key, out value))
                    {
                        throw new KeyNotFoundException();
                    }
                    return value;
                }
                set
                {
                    if (key == null) throw new ArgumentNullException("key");
                    TValue dummy;
                    TryAddInternal(key, value, true, true, out dummy);
                }
            }
     
            /// <summary>
            /// Gets the number of key/value pairs contained in the <see cref="ConcurrentDictionary{TKey,TValue}">.
            /// </see></summary>
            /// <exception cref="T:System.OverflowException">The dictionary contains too many
            /// elements.</exception>
            /// <value>The number of key/value paris contained in the <see cref="ConcurrentDictionary{TKey,TValue}">.</see></value>
            /// <remarks>Count has snapshot semantics and represents the number of items in the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// at the moment when Count was accessed.</see></remarks>
            public int Count
            {
                get
                {
                    int count = 0;
     
                    int acquiredLocks = 0;
                    try
                    {
                        // Acquire all locks
                        AcquireAllLocks(ref acquiredLocks);
     
                        // Compute the count, we allow overflow
                        for (int i = 0; i < m_countPerLock.Length; i++)
                        {
                            count += m_countPerLock[i];
                        }
     
                    }
                    finally
                    {
                        // Release locks that have been acquired earlier
                        ReleaseLocks(0, acquiredLocks);
                    }
     
                    return count;
                }
            }
     
            /// <summary>
            /// Adds a key/value pair to the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// if the key does not already exist.
            /// </see></summary>
            /// <param name="key">The key of the element to add.
            /// <param name="valueFactory">The function used to generate a value for the key
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="valueFactory"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.OverflowException">The dictionary contains too many
            /// elements.</exception>
            /// <returns>The value for the key.  This will be either the existing value for the key if the
            /// key is already in the dictionary, or the new value for the key as returned by valueFactory
            /// if the key was not in the dictionary.</returns>
            public TValue GetOrAdd(TKey key, Func<tkey, tvalue=""> valueFactory)
            {
                if (key == null) throw new ArgumentNullException("key");
                if (valueFactory == null) throw new ArgumentNullException("valueFactory");
     
                TValue resultingValue;
                if (TryGetValue(key, out resultingValue))
                {
                    return resultingValue;
                }
                TryAddInternal(key, valueFactory(key), false, true, out resultingValue);
                return resultingValue;
            }
     
            /// <summary>
            /// Adds a key/value pair to the <see cref="ConcurrentDictionary{TKey,TValue}">
            /// if the key does not already exist.
            /// </see></summary>
            /// <param name="key">The key of the element to add.
            /// <param name="value">the value to be added, if the key does not already exist
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.OverflowException">The dictionary contains too many
            /// elements.</exception>
            /// <returns>The value for the key.  This will be either the existing value for the key if the
            /// key is already in the dictionary, or the new value if the key was not in the dictionary.</returns>
            public TValue GetOrAdd(TKey key, TValue value)
            {
                if (key == null) throw new ArgumentNullException("key");
     
                TValue resultingValue;
                TryAddInternal(key, value, false, true, out resultingValue);
                return resultingValue;
            }
     
            /// <summary>
            /// Adds a key/value pair to the <see cref="ConcurrentDictionary{TKey,TValue}"> if the key does not already
            /// exist, or updates a key/value pair in the <see cref="ConcurrentDictionary{TKey,TValue}"> if the key
            /// already exists.
            /// </see></see></summary>
            /// <param name="key">The key to be added or whose value should be updated
            /// <param name="addValueFactory">The function used to generate a value for an absent key
            /// <param name="updateValueFactory">The function used to generate a new value for an existing key
            /// based on the key's existing value
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="addValueFactory"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="updateValueFactory"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.OverflowException">The dictionary contains too many
            /// elements.</exception>
            /// <returns>The new value for the key.  This will be either be the result of addValueFactory (if the key was
            /// absent) or the result of updateValueFactory (if the key was present).</returns>
            public TValue AddOrUpdate(TKey key, Func<tkey, tvalue=""> addValueFactory, Func<tkey, tvalue,="" tvalue=""> updateValueFactory)
            {
                if (key == null) throw new ArgumentNullException("key");
                if (addValueFactory == null) throw new ArgumentNullException("addValueFactory");
                if (updateValueFactory == null) throw new ArgumentNullException("updateValueFactory");
     
                TValue newValue, resultingValue;
                while (true)
                {
                    TValue oldValue;
                    if (TryGetValue(key, out oldValue))
                    //key exists, try to update
                    {
                        newValue = updateValueFactory(key, oldValue);
                        if (TryUpdate(key, newValue, oldValue))
                        {
                            return newValue;
                        }
                    }
                    else //try add
                    {
                        newValue = addValueFactory(key);
                        if (TryAddInternal(key, newValue, false, true, out resultingValue))
                        {
                            return resultingValue;
                        }
                    }
                }
            }
     
            /// <summary>
            /// Adds a key/value pair to the <see cref="ConcurrentDictionary{TKey,TValue}"> if the key does not already
            /// exist, or updates a key/value pair in the <see cref="ConcurrentDictionary{TKey,TValue}"> if the key
            /// already exists.
            /// </see></see></summary>
            /// <param name="key">The key to be added or whose value should be updated
            /// <param name="addValue">The value to be added for an absent key
            /// <param name="updateValueFactory">The function used to generate a new value for an existing key based on
            /// the key's existing value
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="updateValueFactory"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.OverflowException">The dictionary contains too many
            /// elements.</exception>
            /// <returns>The new value for the key.  This will be either be the result of addValueFactory (if the key was
            /// absent) or the result of updateValueFactory (if the key was present).</returns>
            public TValue AddOrUpdate(TKey key, TValue addValue, Func<tkey, tvalue,="" tvalue=""> updateValueFactory)
            {
                if (key == null) throw new ArgumentNullException("key");
                if (updateValueFactory == null) throw new ArgumentNullException("updateValueFactory");
                TValue newValue, resultingValue;
                while (true)
                {
                    TValue oldValue;
                    if (TryGetValue(key, out oldValue))
                    //key exists, try to update
                    {
                        newValue = updateValueFactory(key, oldValue);
                        if (TryUpdate(key, newValue, oldValue))
                        {
                            return newValue;
                        }
                    }
                    else //try add
                    {
                        if (TryAddInternal(key, addValue, false, true, out resultingValue))
                        {
                            return resultingValue;
                        }
                    }
                }
            }
     
     
     
            /// <summary>
            /// Gets a value that indicates whether the <see cref="ConcurrentDictionary{TKey,TValue}"> is empty.
            /// </see></summary>
            /// <value>true if the <see cref="ConcurrentDictionary{TKey,TValue}"> is empty; otherwise,
            /// false.</see></value>
            public bool IsEmpty
            {
                get
                {
                    int acquiredLocks = 0;
                    try
                    {
                        // Acquire all locks
                        AcquireAllLocks(ref acquiredLocks);
     
                        for (int i = 0; i < m_countPerLock.Length; i++)
                        {
                            if (m_countPerLock[i] != 0)
                            {
                                return false;
                            }
                        }
                    }
                    finally
                    {
                        // Release locks that have been acquired earlier
                        ReleaseLocks(0, acquiredLocks);
                    }
     
                    return true;
                }
            }
     
            #region IDictionary<tkey,tvalue> members
     
            /// <summary>
            /// Adds the specified key and value to the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}">.
            /// </see></summary>
            /// <param name="key">The object to use as the key of the element to add.
            /// <param name="value">The object to use as the value of the element to add.
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.OverflowException">The dictionary contains too many
            /// elements.</exception>
            /// <exception cref="T:System.ArgumentException">
            /// An element with the same key already exists in the <see cref="ConcurrentDictionary{TKey,TValue}">.</see></exception>
            void IDictionary<tkey, tvalue="">.Add(TKey key, TValue value)
            {
                if (!TryAdd(key, value))
                {
                    throw new ArgumentException(GetResource("ConcurrentDictionary_KeyAlreadyExisted"));
                }
            }
     
            /// <summary>
            /// Removes the element with the specified key from the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}">.
            /// </see></summary>
            /// <param name="key">The key of the element to remove.
            /// <returns>true if the element is successfully remove; otherwise false. This method also returns
            /// false if
            /// <paramref name="key"> was not found in the original <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}">.
            /// </see></paramref></returns>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            bool IDictionary<tkey, tvalue="">.Remove(TKey key)
            {
                TValue throwAwayValue;
                return TryRemove(key, out throwAwayValue);
            }
     
            /// <summary>
            /// Gets a collection containing the keys in the <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}">.
            /// </see></summary>
            /// <value>An <see cref="T:System.Collections.Generic.ICollection{TKey}"> containing the keys in the
            /// <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}">.</see></see></value>
            public ICollection<tkey> Keys
            {
                get { return GetKeys(); }
            }
     
            /// <summary>
            /// Gets a collection containing the values in the <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}">.
            /// </see></summary>
            /// <value>An <see cref="T:System.Collections.Generic.ICollection{TValue}"> containing the values in
            /// the
            /// <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}">.</see></see></value>
            public ICollection<tvalue> Values
            {
                get { return GetValues(); }
            }
            #endregion
     
            #region ICollection<keyvaluepair<tkey,tvalue>> Members
     
            /// <summary>
            /// Adds the specified value to the <see cref="T:System.Collections.Generic.ICollection{TValue}">
            /// with the specified key.
            /// </see></summary>
            /// <param name="keyValuePair">The <see cref="T:System.Collections.Generic.KeyValuePair{TKey,TValue}">
            /// structure representing the key and value to add to the <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}">.
            /// <exception cref="T:System.ArgumentNullException">The <paramref name="keyValuePair"> of <paramref name="keyValuePair"> is null.</paramref></paramref></exception>
            /// <exception cref="T:System.OverflowException">The <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}">
            /// contains too many elements.</see></exception>
            /// <exception cref="T:System.ArgumentException">An element with the same key already exists in the
            /// <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}"></see></exception>
            void ICollection<keyvaluepair<tkey, tvalue="">>.Add(KeyValuePair<tkey, tvalue=""> keyValuePair)
            {
                ((IDictionary<tkey, tvalue="">)this).Add(keyValuePair.Key, keyValuePair.Value);
            }
     
            /// <summary>
            /// Determines whether the <see cref="T:System.Collections.Generic.ICollection{TKey,TValue}">
            /// contains a specific key and value.
            /// </see></summary>
            /// <param name="keyValuePair">The <see cref="T:System.Collections.Generic.KeyValuePair{TKey,TValue}">
            /// structure to locate in the <see cref="T:System.Collections.Generic.ICollection{TValue}">.
            /// <returns>true if the <paramref name="keyValuePair"> is found in the <see cref="T:System.Collections.Generic.ICollection{TKey,TValue}">; otherwise, false.</see></paramref></returns>
            bool ICollection<keyvaluepair<tkey, tvalue="">>.Contains(KeyValuePair<tkey, tvalue=""> keyValuePair)
            {
                TValue value;
                if (!TryGetValue(keyValuePair.Key, out value))
                {
                    return false;
                }
                return EqualityComparer<tvalue>.Default.Equals(value, keyValuePair.Value);
            }
     
            /// <summary>
            /// Gets a value indicating whether the dictionary is read-only.
            /// </summary>
            /// <value>true if the <see cref="T:System.Collections.Generic.ICollection{TKey,TValue}"> is
            /// read-only; otherwise, false. For <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}">, this property always returns
            /// false.</see></see></value>
            bool ICollection<keyvaluepair<tkey, tvalue="">>.IsReadOnly
            {
                get { return false; }
            }
     
            /// <summary>
            /// Removes a key and value from the dictionary.
            /// </summary>
            /// <param name="keyValuePair">The <see cref="T:System.Collections.Generic.KeyValuePair{TKey,TValue}">
            /// structure representing the key and value to remove from the <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}">.
            /// <returns>true if the key and value represented by <paramref name="keyValuePair"> is successfully
            /// found and removed; otherwise, false.</paramref></returns>
            /// <exception cref="T:System.ArgumentNullException">The Key property of <paramref name="keyValuePair"> is a null reference (Nothing in Visual Basic).</paramref></exception>
            bool ICollection<keyvaluepair<tkey, tvalue="">>.Remove(KeyValuePair<tkey, tvalue=""> keyValuePair)
            {
                if (keyValuePair.Key == null) throw new ArgumentNullException(GetResource("ConcurrentDictionary_ItemKeyIsNull"));
     
                TValue throwAwayValue;
                return TryRemoveInternal(keyValuePair.Key, out throwAwayValue, true, keyValuePair.Value);
            }
     
            #endregion
     
            #region IEnumerable Members
     
            /// <summary>Returns an enumerator that iterates through the <see cref="ConcurrentDictionary{TKey,TValue}">.</see></summary>
            /// <returns>An enumerator for the <see cref="ConcurrentDictionary{TKey,TValue}">.</see></returns>
            /// <remarks>
            /// The enumerator returned from the dictionary is safe to use concurrently with
            /// reads and writes to the dictionary, however it does not represent a moment-in-time snapshot
            /// of the dictionary.  The contents exposed through the enumerator may contain modifications
            /// made to the dictionary after <see cref="GetEnumerator"> was called.
            /// </see></remarks>
            IEnumerator IEnumerable.GetEnumerator()
            {
                return ((ConcurrentDictionary<tkey, tvalue="">)this).GetEnumerator();
            }
     
            #endregion
     
            #region IDictionary Members
     
            /// <summary>
            /// Adds the specified key and value to the dictionary.
            /// </summary>
            /// <param name="key">The object to use as the key.
            /// <param name="value">The object to use as the value.
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.OverflowException">The dictionary contains too many
            /// elements.</exception>
            /// <exception cref="T:System.ArgumentException">
            /// <paramref name="key"> is of a type that is not assignable to the key type <typeparamref name="TKey"> of the <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}">. -or-
            /// <paramref name="value"> is of a type that is not assignable to <typeparamref name="TValue">,
            /// the type of values in the <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}">.
            /// -or- A value with the same key already exists in the <see cref="T:System.Collections.Generic.Dictionary{TKey,TValue}">.
            /// </see></see></typeparamref></paramref></see></typeparamref></paramref></exception>
            void IDictionary.Add(object key, object value)
            {
                if (key == null) throw new ArgumentNullException("key");
                if (!(key is TKey)) throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfKeyIncorrect"));
     
                TValue typedValue;
                try
                {
                    typedValue = (TValue)value;
                }
                catch (InvalidCastException)
                {
                    throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfValueIncorrect"));
                }
     
                ((IDictionary<tkey, tvalue="">)this).Add((TKey)key, typedValue);
            }
     
            /// <summary>
            /// Gets whether the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}"> contains an
            /// element with the specified key.
            /// </see></summary>
            /// <param name="key">The key to locate in the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}">.
            /// <returns>true if the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}"> contains
            /// an element with the specified key; otherwise, false.</see></returns>
            /// <exception cref="T:System.ArgumentNullException"> <paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            bool IDictionary.Contains(object key)
            {
                if (key == null) throw new ArgumentNullException("key");
     
                return (key is TKey) && ((ConcurrentDictionary<tkey, tvalue="">)this).ContainsKey((TKey)key);
            }
     
            /// <summary>Provides an <see cref="T:System.Collections.Generics.IDictionaryEnumerator"> for the
            /// <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}">.</see></see></summary>
            /// <returns>An <see cref="T:System.Collections.Generics.IDictionaryEnumerator"> for the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}">.</see></see></returns>
            IDictionaryEnumerator IDictionary.GetEnumerator()
            {
                return new DictionaryEnumerator(this);
            }
     
            /// <summary>
            /// Gets a value indicating whether the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}"> has a fixed size.
            /// </see></summary>
            /// <value>true if the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}"> has a
            /// fixed size; otherwise, false. For <see cref="T:System.Collections.Generic.ConcurrentDictionary{TKey,TValue}">, this property always
            /// returns false.</see></see></value>
            bool IDictionary.IsFixedSize
            {
                get { return false; }
            }
     
            /// <summary>
            /// Gets a value indicating whether the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}"> is read-only.
            /// </see></summary>
            /// <value>true if the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}"> is
            /// read-only; otherwise, false. For <see cref="T:System.Collections.Generic.ConcurrentDictionary{TKey,TValue}">, this property always
            /// returns false.</see></see></value>
            bool IDictionary.IsReadOnly
            {
                get { return false; }
            }
     
            /// <summary>
            /// Gets an <see cref="T:System.Collections.ICollection"> containing the keys of the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}">.
            /// </see></see></summary>
            /// <value>An <see cref="T:System.Collections.ICollection"> containing the keys of the <see cref="T:System.Collections.Generic.IDictionary{TKey,TValue}">.</see></see></value>
            ICollection IDictionary.Keys
            {
                get { return GetKeys(); }
            }
     
            /// <summary>
            /// Removes the element with the specified key from the <see cref="T:System.Collections.IDictionary">.
            /// </see></summary>
            /// <param name="key">The key of the element to remove.
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            void IDictionary.Remove(object key)
            {
                if (key == null) throw new ArgumentNullException("key");
     
                TValue throwAwayValue;
                if (key is TKey)
                {
                    this.TryRemove((TKey)key, out throwAwayValue);
                }
            }
     
            /// <summary>
            /// Gets an <see cref="T:System.Collections.ICollection"> containing the values in the <see cref="T:System.Collections.IDictionary">.
            /// </see></see></summary>
            /// <value>An <see cref="T:System.Collections.ICollection"> containing the values in the <see cref="T:System.Collections.IDictionary">.</see></see></value>
            ICollection IDictionary.Values
            {
                get { return GetValues(); }
            }
     
            /// <summary>
            /// Gets or sets the value associated with the specified key.
            /// </summary>
            /// <param name="key">The key of the value to get or set.
            /// <value>The value associated with the specified key, or a null reference (Nothing in Visual Basic)
            /// if <paramref name="key"> is not in the dictionary or <paramref name="key"> is of a type that is
            /// not assignable to the key type <typeparamref name="TKey"> of the <see cref="T:System.Collections.Generic.ConcurrentDictionary{TKey,TValue}">.</see></typeparamref></paramref></paramref></value>
            /// <exception cref="T:System.ArgumentNullException"><paramref name="key"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.ArgumentException">
            /// A value is being assigned, and <paramref name="key"> is of a type that is not assignable to the
            /// key type <typeparamref name="TKey"> of the <see cref="T:System.Collections.Generic.ConcurrentDictionary{TKey,TValue}">. -or- A value is being
            /// assigned, and <paramref name="key"> is of a type that is not assignable to the value type
            /// <typeparamref name="TValue"> of the <see cref="T:System.Collections.Generic.ConcurrentDictionary{TKey,TValue}">
            /// </see></typeparamref></paramref></see></typeparamref></paramref></exception>
            object IDictionary.this[object key]
            {
                get
                {
                    if (key == null) throw new ArgumentNullException("key");
     
                    TValue value;
                    if (key is TKey && this.TryGetValue((TKey)key, out value))
                    {
                        return value;
                    }
     
                    return null;
                }
                set
                {
                    if (key == null) throw new ArgumentNullException("key");
     
                    if (!(key is TKey)) throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfKeyIncorrect"));
                    if (!(value is TValue)) throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfValueIncorrect"));
     
                    ((ConcurrentDictionary<tkey, tvalue="">)this)[(TKey)key] = (TValue)value;
                }
            }
     
            #endregion
     
            #region ICollection Members
     
            /// <summary>
            /// Copies the elements of the <see cref="T:System.Collections.ICollection"> to an array, starting
            /// at the specified array index.
            /// </see></summary>
            /// <param name="array">The one-dimensional array that is the destination of the elements copied from
            /// the <see cref="T:System.Collections.ICollection">. The array must have zero-based
            /// indexing.
            /// <param name="index">The zero-based index in <paramref name="array"> at which copying
            /// begins.
            /// <exception cref="T:System.ArgumentNullException"><paramref name="array"> is a null reference
            /// (Nothing in Visual Basic).</paramref></exception>
            /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"> is less than
            /// 0.</paramref></exception>
            /// <exception cref="T:System.ArgumentException"><paramref name="index"> is equal to or greater than
            /// the length of the <paramref name="array">. -or- The number of elements in the source <see cref="T:System.Collections.ICollection">
            /// is greater than the available space from <paramref name="index"> to the end of the destination
            /// <paramref name="array">.</paramref></paramref></see></paramref></paramref></exception>
            void ICollection.CopyTo(Array array, int index)
            {
                if (array == null) throw new ArgumentNullException("array");
                if (index < 0) throw new ArgumentOutOfRangeException("index", GetResource("ConcurrentDictionary_IndexIsNegative"));
     
                int locksAcquired = 0;
                try
                {
                    AcquireAllLocks(ref locksAcquired);
     
                    int count = 0;
     
                    for (int i = 0; i < m_locks.Length; i++)
                    {
                        count += m_countPerLock[i];
                    }
     
                    if (array.Length - count < index || count < 0) //"count" itself or "count + index" can overflow
                    {
                        throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayNotLargeEnough"));
                    }
     
                    // To be consistent with the behavior of ICollection.CopyTo() in Dictionary<tkey,tvalue>,
                    // we recognize three types of target arrays:
                    //    - an array of KeyValuePair<tkey, tvalue=""> structs
                    //    - an array of DictionaryEntry structs
                    //    - an array of objects
     
                    KeyValuePair<tkey, tvalue="">[] pairs = array as KeyValuePair<tkey, tvalue="">[];
                    if (pairs != null)
                    {
                        CopyToPairs(pairs, index);
                        return;
                    }
     
                    DictionaryEntry[] entries = array as DictionaryEntry[];
                    if (entries != null)
                    {
                        CopyToEntries(entries, index);
                        return;
                    }
     
                    object[] objects = array as object[];
                    if (objects != null)
                    {
                        CopyToObjects(objects, index);
                        return;
                    }
     
                    throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayIncorrectType"), "array");
                }
                finally
                {
                    ReleaseLocks(0, locksAcquired);
                }
            }
     
            /// <summary>
            /// Gets a value indicating whether access to the <see cref="T:System.Collections.ICollection"> is
            /// synchronized with the SyncRoot.
            /// </see></summary>
            /// <value>true if access to the <see cref="T:System.Collections.ICollection"> is synchronized
            /// (thread safe); otherwise, false. For <see cref="T:System.Collections.Concurrent.ConcurrentDictionary{TKey,TValue}">, this property always
            /// returns false.</see></see></value>
            bool ICollection.IsSynchronized
            {
                get { return false; }
            }
     
            /// <summary>
            /// Gets an object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection">. This property is not supported.
            /// </see></summary>
            /// <exception cref="T:System.NotSupportedException">The SyncRoot property is not supported.</exception>
            object ICollection.SyncRoot
            {
                get
                {
                    throw new NotSupportedException(Environment.GetResourceString("ConcurrentCollection_SyncRoot_NotSupported"));
                }
            }
     
            #endregion
     
            /// <summary>
            /// Replaces the internal table with a larger one. To prevent multiple threads from resizing the
            /// table as a result of ----s, the table of buckets that was deemed too small is passed in as
            /// an argument to GrowTable(). GrowTable() obtains a lock, and then checks whether the bucket
            /// table has been replaced in the meantime or not.
            /// </summary>
            /// <param name="buckets">Reference to the bucket table that was deemed too small.
            private void GrowTable(Node[] buckets)
            {
                int locksAcquired = 0;
                try
                {
                    // The thread that first obtains m_locks[0] will be the one doing the resize operation
                    AcquireLocks(0, 1, ref locksAcquired);
     
                    // Make sure nobody resized the table while we were waiting for lock 0:
                    if (buckets != m_buckets)
                    {
                        // We assume that since the table reference is different, it was already resized. If we ever
                        // decide to do table shrinking, or replace the table for other reasons, we will have to revisit
                        // this logic.
                        return;
                    }
     
                    // Compute the new table size. We find the smallest integer larger than twice the previous table size, and not divisible by
                    // 2,3,5 or 7. We can consider a different table-sizing policy in the future.
                    int newLength;
                    try
                    {
                        checked
                        {
                            // Double the size of the buckets table and add one, so that we have an odd integer.
                            newLength = buckets.Length * 2 + 1;
     
                            // Now, we only need to check odd integers, and find the first that is not divisible
                            // by 3, 5 or 7.
                            while (newLength % 3 == 0 || newLength % 5 == 0 || newLength % 7 == 0)
                            {
                                newLength += 2;
                            }
     
                            Assert(newLength % 2 != 0);
                        }
                    }
                    catch (OverflowException)
                    {
                        // If we were to resize the table, its new size will not fit into a 32-bit signed int. Just return.
                        return;
                    }
     
                    Node[] newBuckets = new Node[newLength];
                    int[] newCountPerLock = new int[m_locks.Length];
     
                    // Now acquire all other locks for the table
                    AcquireLocks(1, m_locks.Length, ref locksAcquired);
     
                    // Copy all data into a new table, creating new nodes for all elements
                    for (int i = 0; i < buckets.Length; i++)
                    {
                        Node current = buckets[i];
                        while (current != null)
                        {
                            Node next = current.m_next;
                            int newBucketNo, newLockNo;
                            GetBucketAndLockNo(current.m_hashcode, out newBucketNo, out newLockNo, newBuckets.Length);
     
                            newBuckets[newBucketNo] = new Node(current.m_key, current.m_value, current.m_hashcode, newBuckets[newBucketNo]);
     
                            checked
                            {
                                newCountPerLock[newLockNo]++;
                            }
     
                            current = next;
                        }
                    }
     
                    // And finally adjust m_buckets and m_countPerLock to point to data for the new table
                    m_buckets = newBuckets;
                    m_countPerLock = newCountPerLock;
     
                }
                finally
                {
                    // Release all locks that we took earlier
                    ReleaseLocks(0, locksAcquired);
                }
            }
     
            /// <summary>
            /// Computes the bucket and lock number for a particular key.
            /// </summary>
            private void GetBucketAndLockNo(
                    int hashcode, out int bucketNo, out int lockNo, int bucketCount)
            {
                bucketNo = (hashcode & 0x7fffffff) % bucketCount;
                lockNo = bucketNo % m_locks.Length;
     
                Assert(bucketNo >= 0 && bucketNo < bucketCount);
                Assert(lockNo >= 0 && lockNo < m_locks.Length);
            }
     
            /// <summary>
            /// The number of concurrent writes for which to optimize by default.
            /// </summary>
            private static int DefaultConcurrencyLevel
            {
     
                get { return DEFAULT_CONCURRENCY_MULTIPLIER * Environment.ProcessorCount; }
            }
     
            /// <summary>
            /// Acquires all locks for this hash table, and increments locksAcquired by the number
            /// of locks that were successfully acquired. The locks are acquired in an increasing
            /// order.
            /// </summary>
            private void AcquireAllLocks(ref int locksAcquired)
            {
    #if !FEATURE_PAL
                if (CDSCollectionETWBCLProvider.Log.IsEnabled())
                {
                    CDSCollectionETWBCLProvider.Log.ConcurrentDictionary_AcquiringAllLocks(m_buckets.Length);
                }
    #endif //!FEATURE_PAL
     
                AcquireLocks(0, m_locks.Length, ref locksAcquired);
                Assert(locksAcquired == m_locks.Length);
            }
     
            /// <summary>
            /// Acquires a contiguous range of locks for this hash table, and increments locksAcquired
            /// by the number of locks that were successfully acquired. The locks are acquired in an
            /// increasing order.
            /// </summary>
            private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired)
            {
                Assert(fromInclusive <= toExclusive);
     
                for (int i = fromInclusive; i < toExclusive; i++)
                {
                    bool lockTaken = false;
                    try
                    {
    #if CDS_COMPILE_JUST_THIS
                        Monitor.Enter(m_locks[i]);
                        lockTaken = true;
    #else
                        Monitor.Enter(m_locks[i], ref lockTaken);
    #endif
                    }
                    finally
                    {
                        if (lockTaken)
                        {
                            locksAcquired++;
                        }
                    }
                }
            }
     
            /// <summary>
            /// Releases a contiguous range of locks.
            /// </summary>
            private void ReleaseLocks(int fromInclusive, int toExclusive)
            {
                Assert(fromInclusive <= toExclusive);
     
                for (int i = fromInclusive; i < toExclusive; i++)
                {
                    Monitor.Exit(m_locks[i]);
                }
            }
     
            /// <summary>
            /// Gets a collection containing the keys in the dictionary.
            /// </summary>
            private ReadOnlyCollection<tkey> GetKeys()
            {
                int locksAcquired = 0;
                try
                {
                    AcquireAllLocks(ref locksAcquired);
                    List<tkey> keys = new List<tkey>();
     
                    for (int i = 0; i < m_buckets.Length; i++)
                    {
                        Node current = m_buckets[i];
                        while (current != null)
                        {
                            keys.Add(current.m_key);
                            current = current.m_next;
                        }
                    }
     
                    return new ReadOnlyCollection<tkey>(keys);
                }
                finally
                {
                    ReleaseLocks(0, locksAcquired);
                }
            }
     
            /// <summary>
            /// Gets a collection containing the values in the dictionary.
            /// </summary>
            private ReadOnlyCollection<tvalue> GetValues()
            {
                int locksAcquired = 0;
                try
                {
                    AcquireAllLocks(ref locksAcquired);
                    List<tvalue> values = new List<tvalue>();
     
                    for (int i = 0; i < m_buckets.Length; i++)
                    {
                        Node current = m_buckets[i];
                        while (current != null)
                        {
                            values.Add(current.m_value);
                            current = current.m_next;
                        }
                    }
     
                    return new ReadOnlyCollection<tvalue>(values);
                }
                finally
                {
                    ReleaseLocks(0, locksAcquired);
                }
            }
     
            /// <summary>
            /// A helper method for asserts.
            /// </summary>
            [Conditional("DEBUG")]
            private void Assert(bool condition)
            {
    #if CDS_COMPILE_JUST_THIS
                if (!condition)
                {
                    throw new Exception("Assertion failed.");
                }
    #else
                Contract.Assert(condition);
    #endif
            }
     
            /// <summary>
            /// A helper function to obtain the string for a particular resource key.
            /// </summary>
            /// <param name="key">
            /// <returns></returns>
            private string GetResource(string key)
            {
                Assert(key != null);
     
    #if CDS_COMPILE_JUST_THIS
                return key;
    #else
                return Environment.GetResourceString(key);
    #endif
            }
     
            /// <summary>
            /// A node in a singly-linked list representing a particular hash table bucket.
            /// </summary>
            private class Node
            {
                internal TKey m_key;
                internal TValue m_value;
                internal volatile Node m_next;
                internal int m_hashcode;
     
                internal Node(TKey key, TValue value, int hashcode)
                    : this(key, value, hashcode, null)
                {
                }
     
                internal Node(TKey key, TValue value, int hashcode, Node next)
                {
                    m_key = key;
                    m_value = value;
                    m_next = next;
                    m_hashcode = hashcode;
                }
            }
     
            /// <summary>
            /// A private class to represent enumeration over the dictionary that implements the
            /// IDictionaryEnumerator interface.
            /// </summary>
            private class DictionaryEnumerator : IDictionaryEnumerator
            {
                IEnumerator<keyvaluepair<tkey, tvalue="">> m_enumerator; // Enumerator over the dictionary.
     
                internal DictionaryEnumerator(ConcurrentDictionary<tkey, tvalue=""> dictionary)
                {
                    m_enumerator = dictionary.GetEnumerator();
                }
     
                public DictionaryEntry Entry
                {
                    get { return new DictionaryEntry(m_enumerator.Current.Key, m_enumerator.Current.Value); }
                }
     
                public object Key
                {
                    get { return m_enumerator.Current.Key; }
                }
     
                public object Value
                {
                    get { return m_enumerator.Current.Value; }
                }
     
                public object Current
                {
                    get { return this.Entry; }
                }
     
                public bool MoveNext()
                {
                    return m_enumerator.MoveNext();
                }
     
                public void Reset()
                {
                    m_enumerator.Reset();
                }
            }
     
            /// <summary>
            /// Get the data array to be serialized
            /// </summary>
            [OnSerializing]
            private void OnSerializing(StreamingContext context)
            {
                // save the data into the serialization array to be saved
                m_serializationArray = ToArray();
                m_serializationConcurrencyLevel = m_locks.Length;
                m_serializationCapacity = m_buckets.Length;
            }
     
            /// <summary>
            /// Construct the dictionary from a previously seiralized one
            /// </summary>
            [OnDeserialized]
            private void OnDeserialized(StreamingContext context)
            {
                KeyValuePair<tkey, tvalue="">[] array = m_serializationArray;
     
                m_buckets = new Node[m_serializationCapacity];
                m_countPerLock = new int[m_serializationConcurrencyLevel];
     
                m_locks = new object[m_serializationConcurrencyLevel];
                for (int i = 0; i < m_locks.Length; i++)
                {
                    m_locks[i] = new object();
                }
     
                InitializeFromCollection(array);
                m_serializationArray = null;
     
            }
        }
    }

  • 相关阅读:
    [PHP] PHP 7.4.4错误修复版本的更改日志
    [Linux] 协程是不是我想的这样
    [前端] 代码中执行绑定元素的指定事件trigger方法
    [PHP] 中英双语网站的设计思路
    [网络] 使用wireshark抓包数据
    [MySQL] 有没有解决幻读问题
    [PHP] PDO 提供了三种不同的错误处理模式
    [Linux] 使用vmstat查看系统的负载情况
    [MySQL] innoDB引擎的主键与聚簇索引
    [PHP] 检测文件是否有病毒的实现逻辑
  • 原文地址:https://www.cnblogs.com/vveiliang/p/6659254.html
Copyright © 2020-2023  润新知