コード例 #1
0
        /// A wait free alternative to offer which fails on CAS failure.
        /// @param e new element, not null
        /// @return 1 if next element cannot be filled, -1 if CAS failed, 0 if successful
        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 :)
        }
コード例 #2
0
        /// {@inheritDoc}
        /// <p />
        /// IMPLEMENTATION NOTES:
        /// <br />
        /// Lock free peek using ordered loads. As class name suggests access is limited to a single thread.
        /// @see java.util.Queue#poll()
        public override bool TryPeek(out T item)
        {
            // Copy field to avoid re-reading after volatile load
            T[] buffer = this.Buffer;

            long consumerIndex = this.ConsumerIndex; // LoadLoad
            long offset        = this.CalcElementOffset(consumerIndex);
            T    e             = RefArrayAccessUtil.LvElement(buffer, offset);

            if (null == e)
            {
                // NOTE: Queue may not actually be empty in the case of a producer (P1) being interrupted after
                // winning the CAS on offer but before storing the element in the queue. Other producers may go on
                // to fill up the queue after this element.

                if (consumerIndex != this.ProducerIndex)
                {
                    do
                    {
                        e = RefArrayAccessUtil.LvElement(buffer, offset);
                    }while (e == null);
                }
                else
                {
                    item = default(T);
                    return(false);
                }
            }
            item = e;
            return(true);
        }
コード例 #3
0
        /// {@inheritDoc}
        /// <br />
        /// IMPLEMENTATION NOTES:
        /// <br />
        /// Lock free offer using a single CAS. As class name suggests access is permitted to many threads
        /// concurrently.
        /// @see java.util.Queue#offer(java.lang.Object)
        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 :)
        }
コード例 #4
0
 /// A volatile load (load + LoadLoad barrier) of an element from a given offset.
 /// @param offset computed via {@link ConcurrentCircularArrayQueue#calcElementOffset(long)}
 /// @return the element at the offset
 protected T LvElement(long offset) => RefArrayAccessUtil.LvElement(this.Buffer, offset);
コード例 #5
0
 /// An ordered store(store + StoreStore barrier) of an element to a given offset
 /// @param offset computed via {@link ConcurrentCircularArrayQueue#calcElementOffset(long)}
 /// @param e an orderly kitty
 protected void SoElement(long offset, T e) => RefArrayAccessUtil.SoElement(this.Buffer, offset, e);
コード例 #6
0
 /// @param index desirable element index
 /// @return the offset in bytes within the array for a given index.
 protected long CalcElementOffset(long index) => RefArrayAccessUtil.CalcElementOffset(index, this.Mask);