예제 #1
0
            /// <summary>
            /// Attempt to add "value" to the table, hashed by an embedded string key.  If a value having the same key already exists,
            /// then return the existing value in "newValue".  Otherwise, return the newly added value in "newValue".
            ///
            /// If the hash table is full, return false.  Otherwise, return true.
            /// </summary>
            public bool TryAdd(TValue value, out TValue newValue)
            {
                int    newEntry, entryIndex;
                string key;
                int    hashCode;

                // Assume "value" will be added and returned as "newValue"
                newValue = value;

                // Extract the key from the value.  If it's null, then value is invalid and does not need to be added to table.
                key = extractKey(value);
                if (key == null)
                {
                    return(true);
                }

                // Compute hash code over entire length of key
                hashCode = ComputeHashCode(key, 0, key.Length);

                // Assume value is not yet in the hash table, and prepare to add it (if table is full, return false).
                // Use the entry index returned from Increment, which will never be zero, as zero conflicts with EndOfList.
                // Although this means that the first entry will never be used, it avoids the need to initialize all
                // starting buckets to the EndOfList value.
                newEntry = Interlocked.Increment(ref numEntries);
                if (newEntry < 0 || newEntry >= buckets.Length)
                {
                    return(false);
                }

                entries[newEntry].Value    = value;
                entries[newEntry].HashCode = hashCode;

                // Ensure that all writes to the entry can't be reordered past this barrier (or other threads might see new entry
                // in list before entry has been initialized!).
#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 <Entry[]>(ref entries, null, null);
#endif // SILVERLIGHT

                // Loop until a matching entry is found, a new entry is added, or linked list is found to be full
                entryIndex = 0;
                while (!FindEntry(hashCode, key, 0, key.Length, ref entryIndex))
                {
                    // PUBLISH (buckets slot)
                    // No matching entry found, so add the new entry to the end of the list ("entryIndex" is index of last entry)
                    if (entryIndex == 0)
                    {
                        entryIndex = Interlocked.CompareExchange(ref buckets[hashCode & (buckets.Length - 1)], newEntry, EndOfList);
                    }
                    else
                    {
                        entryIndex = Interlocked.CompareExchange(ref entries[entryIndex].Next, newEntry, EndOfList);
                    }

                    // Return true only if the CompareExchange succeeded (happens when replaced value is EndOfList).
                    // Return false if the linked list turned out to be full because another thread is currently resizing
                    // the hash table.  In this case, entries[newEntry] is orphaned (not part of any linked list) and the
                    // Add needs to be performed on the new hash table.  Otherwise, keep looping, looking for new end of list.
                    if (entryIndex <= EndOfList)
                    {
                        return(entryIndex == EndOfList);
                    }
                }

                // Another thread already added the value while this thread was trying to add, so return that instance instead.
                // Note that entries[newEntry] will be orphaned (not part of any linked list) in this case
                newValue = entries[entryIndex].Value;

                return(true);
            }
 public bool CompareAndSet(T expect, T update)
 {
     return(Interlocked.CompareExchange(ref _value, update, expect) == expect);
 }
예제 #3
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);
            }
예제 #4
0
 public void Reset()
 {
     Interlocked.CompareExchange(ref signal, 0x00, 0x01);
 }
예제 #5
0
 public void Set()
 {
     Interlocked.CompareExchange(ref signal, 0x01, 0x00);
 }
예제 #6
0
 public static Object LoadReferenceTypeField(IntPtr address)
 {
     return(Interlocked.CompareExchange <Object>(address, null, null));
 }
예제 #7
0
 internal new UIntPtr CompareExchangeMUW(UIntPtr newValue,
                                         UIntPtr oldValue)
 {
     return(Interlocked.CompareExchange(ref this.preHeader.muw.value,
                                        newValue, oldValue));
 }
예제 #8
0
        private bool TryStartCalculation()
        {
            var result = Interlocked.CompareExchange(ref _state, Calculating, Invalid);

            return(result == Invalid);
        }