Exemple #1
0
 /// <summary>
 /// Removes all the elements.
 /// </summary>
 public void Clear()
 {
     _entriesOld = null;
     _entriesNew = new FixedSizeSetBucket <T>(INT_DefaultCapacity, _comparer);
     Thread.VolatileWrite(ref _status, (int)BucketStatus.Free);
     Thread.VolatileWrite(ref _count, 0);
     _revision++;
 }
Exemple #2
0
 private bool ContainsExtracted(T item, FixedSizeSetBucket <T> entries)
 {
     for (int attempts = 0; attempts < _maxProbing; attempts++)
     {
         if (entries.Contains(item, attempts) != -1)
         {
             return(true);
         }
     }
     return(false);
 }
Exemple #3
0
 private bool TryGetExtracted(int index, FixedSizeSetBucket <T> entries, out T item)
 {
     item = default(T);
     if (entries != null)
     {
         if (entries.TryGet(index, out item))
         {
             return(true);
         }
     }
     return(false);
 }
Exemple #4
0
 private bool RemoveExtracted(T item, FixedSizeSetBucket <T> entries)
 {
     if (entries != null)
     {
         for (int attempts = 0; attempts < _maxProbing; attempts++)
         {
             if (entries.Remove(item, attempts) != -1)
             {
                 return(true);
             }
         }
     }
     return(false);
 }
Exemple #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SetBucket{TValue}" /> class.
 /// </summary>
 /// <param name="capacity">The initial capacity.</param>
 /// <param name="comparer">The 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 SetBucket(int capacity, IEqualityComparer <T> 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
     {
         _comparer   = comparer ?? EqualityComparer <T> .Default;
         _entriesOld = null;
         _entriesNew = new FixedSizeSetBucket <T>(capacity, _comparer);
         _maxProbing = maxProbing;
     }
 }
Exemple #6
0
 //HACK
 private int SetExtracted(T item, FixedSizeSetBucket <T> entries, out bool isNew)
 {
     isNew = false;
     if (entries != null)
     {
         for (int attempts = 0; attempts < _maxProbing; attempts++)
         {
             int index = entries.Set(item, attempts, out isNew);
             if (index != -1)
             {
                 return(index);
             }
         }
     }
     return(-1);
 }
Exemple #7
0
 private int AddExtracted(T item, FixedSizeSetBucket <T> entries, out bool isCollision)
 {
     isCollision = true;
     if (entries != null)
     {
         for (int attempts = 0; attempts < _maxProbing; attempts++)
         {
             int index = entries.Add(item, attempts, out isCollision);
             if (index != -1 || !isCollision)
             {
                 return(index);
             }
         }
     }
     return(-1);
 }
Exemple #8
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 FixedSizeSetBucket <T>(newCapacity, _comparer));
                            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);
                        T   item;
                        int index = Interlocked.Increment(ref _copyPosition);
                        for (; index < old.Capacity; index = Interlocked.Increment(ref _copyPosition))
                        {
                            if (old.TryGet(index, out item))
                            {
                                // We have read an item, so let's try to add it to the new storage
                                bool dummy;

                                //HACK
                                if (SetExtracted(item, _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 != 0);
        }