Ejemplo n.º 1
0
        /// <summary>
        /// A wait-free alternative to <see cref="TryEnqueue"/>, which fails on compare-and-swap failure.
        /// </summary>
        /// <param name="e">The item to enqueue.</param>
        /// <returns><c>1</c> if next element cannot be filled, <c>-1</c> if CAS failed, and <c>0</c> if successful.</returns>
        public int WeakEnqueue(T e)
        {
            Contract.Requires(e != null);

            long mask               = this.Mask;
            long capacity           = mask + 1;
            long currentTail        = this.ProducerIndex;      // LoadLoad
            long consumerIndexCache = this.ConsumerIndexCache; // LoadLoad
            long wrapPoint          = currentTail - capacity;

            if (consumerIndexCache <= wrapPoint)
            {
                long currHead = this.ConsumerIndex; // LoadLoad
                if (currHead <= wrapPoint)
                {
                    return(1); // FULL :(
                }
                else
                {
                    this.ConsumerIndexCache = currHead; // StoreLoad
                }
            }

            // look Ma, no loop!
            if (!this.TrySetProducerIndex(currentTail, currentTail + 1))
            {
                return(-1); // CAS FAIL :(
            }

            // Won CAS, move on to storing
            long offset = RefArrayAccessUtil.CalcElementOffset(currentTail, mask);

            this.SoElement(offset, e);
            return(0); // AWESOME :)
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Lock free Enqueue operation, using a single compare-and-swap. As the class name suggests, access is
        /// permitted to many threads concurrently.
        /// </summary>
        /// <param name="e">The item to enqueue.</param>
        /// <returns><c>true</c> if the item was added successfully, otherwise <c>false</c>.</returns>
        /// <seealso cref="IQueue{T}.TryEnqueue"/>
        public override bool TryEnqueue(T e)
        {
            Contract.Requires(e != null);

            // use a cached view on consumer index (potentially updated in loop)
            long mask               = this.Mask;
            long capacity           = mask + 1;
            long consumerIndexCache = this.ConsumerIndexCache; // LoadLoad
            long currentProducerIndex;

            do
            {
                currentProducerIndex = this.ProducerIndex; // LoadLoad
                long wrapPoint = currentProducerIndex - capacity;
                if (consumerIndexCache <= wrapPoint)
                {
                    long currHead = this.ConsumerIndex; // LoadLoad
                    if (currHead <= wrapPoint)
                    {
                        return(false); // FULL :(
                    }
                    else
                    {
                        // update shared cached value of the consumerIndex
                        this.ConsumerIndexCache = currHead; // StoreLoad
                        // update on stack copy, we might need this value again if we lose the CAS.
                        consumerIndexCache = currHead;
                    }
                }
            } while (!this.TrySetProducerIndex(currentProducerIndex, currentProducerIndex + 1));

            // NOTE: the new producer index value is made visible BEFORE the element in the array. If we relied on
            // the index visibility to poll() we would need to handle the case where the element is not visible.

            // Won CAS, move on to storing
            long offset = RefArrayAccessUtil.CalcElementOffset(currentProducerIndex, mask);

            this.SoElement(offset, e); // StoreStore
            return(true);              // AWESOME :)
        }
 /// <summary>
 /// Calculates an element offset based on a given array index.
 /// </summary>
 /// <param name="index">The desirable element index.</param>
 /// <returns>The offset in bytes within the array for a given index.</returns>
 protected long CalcElementOffset(long index) => RefArrayAccessUtil.CalcElementOffset(index, this.Mask);