/// <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); }
/// <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 void Reset() { Interlocked.CompareExchange(ref signal, 0x00, 0x01); }
public void Set() { Interlocked.CompareExchange(ref signal, 0x01, 0x00); }
public static Object LoadReferenceTypeField(IntPtr address) { return(Interlocked.CompareExchange <Object>(address, null, null)); }
internal new UIntPtr CompareExchangeMUW(UIntPtr newValue, UIntPtr oldValue) { return(Interlocked.CompareExchange(ref this.preHeader.muw.value, newValue, oldValue)); }
private bool TryStartCalculation() { var result = Interlocked.CompareExchange(ref _state, Calculating, Invalid); return(result == Invalid); }