Exemple #1
0
        /// <summary>
        /// Add a value to the hash table, hashed based on a string key embedded in it.  Return the added value (may be a different object than "value").
        /// </summary>
        public TValue Add(TValue value)
        {
            TValue newValue;

            // Loop until value is in hash table
            while (true)
            {
                // Add new value
                // XHashtableState.TryAdd returns false if hash table is not big enough
                if (_state.TryAdd(value, out newValue))
                {
                    return(newValue);
                }

                // PUBLISH (state)
                // Hash table was not big enough, so resize it.
                // We only want one thread to perform a resize, as it is an expensive operation
                // First thread will perform resize; waiting threads will call Resize(), but should immediately
                // return since there will almost always be space in the hash table resized by the first thread.
                lock (this)
                {
                    XHashtableState newState = _state.Resize();
                    // Use memory barrier to ensure that the resized XHashtableState object is fully constructed before it is assigned
                    Thread.MemoryBarrier();
                    _state = newState;
                }
            }
        }
        public TValue Add(TValue value)
        {
            TValue local;

Label_0000:
            if (this.state.TryAdd(value, out local))
            {
                return(local);
            }
            lock (((XHashtable <TValue>) this))
            {
                XHashtableState <TValue> state = this.state.Resize();
                Thread.MemoryBarrier();
                this.state = state;
                goto Label_0000;
            }
        }
Exemple #3
0
        /// <summary>
        /// Add a value to the hash table, hashed based on a string key embedded in it.  Return the added value (may be a different object than "value").
        /// </summary>
        public TValue Add(TValue value)
        {
            TValue newValue;

            // Loop until value is in hash table
            while (true)
            {
                // Add new value
                // XHashtableState.TryAdd returns false if hash table is not big enough
                if (state.TryAdd(value, out newValue))
                {
                    return(newValue);
                }

                // PUBLISH (state)
                // Hash table was not big enough, so resize it.
                // We only want one thread to perform a resize, as it is an expensive operation
                // First thread will perform resize; waiting threads will call Resize(), but should immediately
                // return since there will almost always be space in the hash table resized by the first thread.
                lock (this)
                {
                    XHashtableState newState = state.Resize();

                    // Use memory barrier to ensure that the resized XHashtableState object is fully constructed before it is assigned
#if !SILVERLIGHT
                    Thread.MemoryBarrier();
#else // SILVERLIGHT
                    // According to this document "http://my/sites/juddhall/ThreadingFeatureCrew/Shared Documents/System.Threading - FX Audit Proposal.docx"
                    // The MemoryBarrier method usage is busted (mostly - don't know about ours) and should be removed.

                    // Replacing with Interlocked.CompareExchange for now (with no effect)
                    //   which will do a very similar thing to MemoryBarrier (it's just slower)
                    System.Threading.Interlocked.CompareExchange <XHashtableState>(ref state, null, null);
#endif // SILVERLIGHT
                    state = newState;
                }
            }
        }
Exemple #4
0
 /// <summary>
 /// Construct a new XHashtable with the specified starting capacity.
 /// </summary>
 public XHashtable(ExtractKeyDelegate extractKey, int capacity)
 {
     _state = new XHashtableState(extractKey, capacity);
 }
Exemple #5
0
            /// <summary>
            /// If this table is not full, then just return "this".  Otherwise, create and return a new table with
            /// additional capacity, and rehash all values in the table.
            /// </summary>
            public XHashtableState Resize()
            {
                // No need to resize if there are open entries
                if (_numEntries < _buckets.Length)
                {
                    return(this);
                }

                int newSize = 0;

                // Determine capacity of resized hash table by first counting number of valid, non-orphaned entries
                // As this count proceeds, close all linked lists so that no additional entries can be added to them
                for (int bucketIdx = 0; bucketIdx < _buckets.Length; bucketIdx++)
                {
                    int entryIdx = _buckets[bucketIdx];

                    if (entryIdx == EndOfList)
                    {
                        // Replace EndOfList with FullList, so that any threads still attempting to add will be forced to resize
                        entryIdx = Interlocked.CompareExchange(ref _buckets[bucketIdx], FullList, EndOfList);
                    }

                    // Loop until we've guaranteed that the list has been counted and closed to further adds
                    while (entryIdx > EndOfList)
                    {
                        // Count each valid entry
                        if (_extractKey(_entries[entryIdx].Value) != null)
                        {
                            newSize++;
                        }

                        if (_entries[entryIdx].Next == EndOfList)
                        {
                            // Replace EndOfList with FullList, so that any threads still attempting to add will be forced to resize
                            entryIdx = Interlocked.CompareExchange(ref _entries[entryIdx].Next, FullList, EndOfList);
                        }
                        else
                        {
                            // Move to next entry in the list
                            entryIdx = _entries[entryIdx].Next;
                        }
                    }
                    Debug.Assert(entryIdx == EndOfList, "Resize() should only be called by one thread");
                }

                // Double number of valid entries; if result is less than current capacity, then use current capacity
                if (newSize < _buckets.Length / 2)
                {
                    newSize = _buckets.Length;
                }
                else
                {
                    newSize = _buckets.Length * 2;

                    if (newSize < 0)
                    {
                        throw new OverflowException();
                    }
                }

                // Create new hash table with additional capacity
                XHashtableState newHashtable = new XHashtableState(_extractKey, newSize);

                // Rehash names (TryAdd will always succeed, since we won't fill the new table)
                // Do not simply walk over entries and add them to table, as that would add orphaned
                // entries.  Instead, walk the linked lists and add each name.
                for (int bucketIdx = 0; bucketIdx < _buckets.Length; bucketIdx++)
                {
                    int    entryIdx = _buckets[bucketIdx];
                    TValue newValue;

                    while (entryIdx > EndOfList)
                    {
                        newHashtable.TryAdd(_entries[entryIdx].Value, out newValue);

                        entryIdx = _entries[entryIdx].Next;
                    }
                    Debug.Assert(entryIdx == FullList, "Linked list should have been closed when it was counted");
                }

                return(newHashtable);
            }
 public XHashtable(ExtractKeyDelegate <TValue> extractKey, int capacity)
 {
     this.state = new XHashtableState <TValue>(extractKey, capacity);
 }