コード例 #1
0
 /// <summary>
 /// Removes all the elements.
 /// </summary>
 public void Clear()
 {
     _entriesOld = null;
     _entriesNew = new FixedSizeHashBucket <TKey, TValue>(INT_DefaultCapacity, _keyComparer);
     Thread.VolatileWrite(ref _status, (int)BucketStatus.Free);
     Thread.VolatileWrite(ref _count, 0);
     _revision++;
 }
コード例 #2
0
 private bool ContainsKeyExtracted(TKey key, FixedSizeHashBucket <TKey, TValue> entries)
 {
     for (int attempts = 0; attempts < _maxProbing; attempts++)
     {
         if (entries.ContainsKey(key, attempts) != -1)
         {
             return(true);
         }
     }
     return(false);
 }
コード例 #3
0
 private bool TryGetExtracted(int index, FixedSizeHashBucket <TKey, TValue> entries, out TKey key, out TValue value)
 {
     value = default(TValue);
     key   = default(TKey);
     if (entries != null)
     {
         if (entries.TryGet(index, out key, out value))
         {
             return(true);
         }
     }
     return(false);
 }
コード例 #4
0
 private bool RemoveExtracted(TKey key, FixedSizeHashBucket <TKey, TValue> entries)
 {
     if (entries != null)
     {
         for (int attempts = 0; attempts < _maxProbing; attempts++)
         {
             if (entries.Remove(key, attempts) != -1)
             {
                 return(true);
             }
         }
     }
     return(false);
 }
コード例 #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="HashBucket{TValue}" /> class.
 /// </summary>
 /// <param name="capacity">The initial capacity.</param>
 /// <param name="comparer">The key comparer.</param>
 /// <param name="maxProbing">The maximum number of steps in linear probing.</param>
 /// <exception cref="System.ArgumentOutOfRangeException">maxProbing;maxProbing must be greater or equal to 1 and less than capacity.</exception>
 public HashBucket(int capacity, IEqualityComparer <TKey> comparer, int maxProbing)
 {
     if (maxProbing < 1 || maxProbing >= capacity)
     {
         throw new ArgumentOutOfRangeException("maxProbing", "maxProbing must be greater or equal to 1 and less than capacity.");
     }
     else
     {
         _keyComparer = comparer ?? EqualityComparer <TKey> .Default;
         _entriesOld  = null;
         _entriesNew  = new FixedSizeHashBucket <TKey, TValue>(capacity, _keyComparer);
         _maxProbing  = maxProbing;
     }
 }
コード例 #6
0
 private bool TryGetValueExtracted(TKey key, FixedSizeHashBucket <TKey, TValue> entries, out TValue value)
 {
     value = default(TValue);
     if (entries != null)
     {
         for (int attempts = 0; attempts < _maxProbing; attempts++)
         {
             if (entries.TryGetValue(key, attempts, out value) != -1)
             {
                 return(true);
             }
         }
     }
     return(false);
 }
コード例 #7
0
 private int TryAddExtracted(TKey key, TValue value, FixedSizeHashBucket <TKey, TValue> entries, out KeyValuePair <TKey, TValue> previous)
 {
     previous = default(KeyValuePair <TKey, TValue>);
     if (entries != null)
     {
         for (int attempts = 0; attempts < _maxProbing; attempts++)
         {
             int index = entries.TryAdd(key, value, attempts, out previous);
             if (index != -1)
             {
                 return(index);
             }
         }
     }
     return(-1);
 }
コード例 #8
0
 private int SetExtracted(TKey key, TValue value, FixedSizeHashBucket <TKey, TValue> entries, out bool isNew)
 {
     isNew = false;
     if (entries != null)
     {
         for (int attempts = 0; attempts < _maxProbing; attempts++)
         {
             int index = entries.Set(key, value, attempts, out isNew);
             if (index != -1)
             {
                 return(index);
             }
         }
     }
     return(-1);
 }
コード例 #9
0
 private int AddExtracted(TKey key, TValue value, FixedSizeHashBucket <TKey, TValue> entries, out bool isCollision)
 {
     isCollision = true;
     if (entries != null)
     {
         for (int attempts = 0; attempts < _maxProbing; attempts++)
         {
             int index = entries.Add(key, value, attempts, out isCollision);
             if (index != -1 || !isCollision)
             {
                 return(index);
             }
         }
     }
     return(-1);
 }
コード例 #10
0
        private void CooperativeGrow()
        {
            int status;

            do
            {
                status = Thread.VolatileRead(ref _status);
                int oldStatus;
                switch (status)
                {
                case (int)BucketStatus.GrowRequested:

                    // This area is only accessed by one thread, if that thread is aborted, we are doomed.
                    // This class is not abort safe
                    // If a thread is being aborted here it's pending operation will be lost and there is risk of a livelock
                    var priority = Thread.CurrentThread.Priority;
                    oldStatus = Interlocked.CompareExchange(ref _status, (int)BucketStatus.Waiting, (int)BucketStatus.GrowRequested);
                    if (oldStatus == (int)BucketStatus.GrowRequested)
                    {
                        try
                        {
                            // The progress of other threads depend of this one, we should not allow a priority inversion.
                            Thread.CurrentThread.Priority = ThreadPriority.Highest;
                            //_copyPosition is set to -1. _copyPosition is incremented before it is used, so the first time it is used it will be 0.
                            Thread.VolatileWrite(ref _copyPosition, -1);
                            //The new capacity is twice the old capacity, the capacity must be a power of two.
                            var newCapacity = _entriesNew.Capacity * 2;
                            _entriesOld = Interlocked.Exchange(ref _entriesNew, new FixedSizeHashBucket <TKey, TValue>(newCapacity, _keyComparer));
                            oldStatus   = Interlocked.CompareExchange(ref _status, (int)BucketStatus.Copy, (int)BucketStatus.Waiting);
                        }
                        finally
                        {
                            Thread.CurrentThread.Priority = priority;
                            _revision++;
                        }
                    }
                    break;

                case (int)BucketStatus.Waiting:

                    // This is the whole reason why this datastructure is not wait free.
                    // Testing shows that it is uncommon that a thread enters here.
                    // _status is 2 only for a short period.
                    // Still, it happens, so this is needed for correctness.
                    // Going completely wait-free adds complexity with deminished value.
                    Thread.SpinWait(INT_SpinWaitHint);
                    if (Thread.VolatileRead(ref _status) == 2)
                    {
                        Thread.Sleep(0);
                    }
                    break;

                case (int)BucketStatus.Copy:

                    // It is time to cooperate to copy the old storage to the new one
                    var old = _entriesOld;
                    if (old != null)
                    {
                        // This class is not abort safe
                        // If a thread is being aborted here it will causing lost items.
                        _revision++;
                        Interlocked.Increment(ref _copyingThreads);
                        TKey   key;
                        TValue value;
                        int    index = Interlocked.Increment(ref _copyPosition);
                        for (; index < old.Capacity; index = Interlocked.Increment(ref _copyPosition))
                        {
                            if (old.TryGet(index, out key, out value))
                            {
                                // We have read an item, so let's try to add it to the new storage
                                bool dummy;
                                if (SetExtracted(key, value, _entriesNew, out dummy) == -1)
                                {
                                    GC.KeepAlive(dummy);
                                }
                            }
                        }
                        Interlocked.CompareExchange(ref _status, (int)BucketStatus.CopyCleanup, (int)BucketStatus.Copy);
                        _revision++;
                        Interlocked.Decrement(ref _copyingThreads);
                    }
                    break;

                case (int)BucketStatus.CopyCleanup:

                    // Our copy is finished, we don't need the old storage anymore
                    oldStatus = Interlocked.CompareExchange(ref _status, (int)BucketStatus.Waiting, (int)BucketStatus.CopyCleanup);
                    if (oldStatus == (int)BucketStatus.CopyCleanup)
                    {
                        _revision++;
                        Interlocked.Exchange(ref _entriesOld, null);
                        Interlocked.CompareExchange(ref _status, (int)BucketStatus.Free, (int)BucketStatus.Waiting);
                    }
                    break;

                default:
                    break;
                }
            }while (status != (int)BucketStatus.Free);
        }