/// <summary>
        /// Lock free peek using ordered loads. As class name suggests access is limited to a single thread.
        /// </summary>
        /// <param name="item">The peeked item.</param>
        /// <returns><c>true</c> if an item was retrieved, otherwise <c>false</c>.</returns>
        /// <seealso cref="IQueue{T}.TryPeek"/>
        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);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Lock free poll using ordered loads/stores. As class name suggests, access is limited to a single thread.
        /// </summary>
        /// <param name="item">The dequeued item.</param>
        /// <returns><c>true</c> if an item was retrieved, otherwise <c>false</c>.</returns>
        /// <seealso cref="IQueue{T}.TryDequeue"/>
        public override bool TryDequeue(out T item)
        {
            long consumerIndex = this.ConsumerIndex; // LoadLoad
            long offset        = this.CalcElementOffset(consumerIndex);

            // Copy field to avoid re-reading after volatile load
            T[] buffer = this.Buffer;

            // If we can't see the next available element we can't poll
            T e = RefArrayAccessUtil.LvElement(buffer, offset); // LoadLoad

            if (e is null)
            {
                // 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 is null);
                }
                else
                {
                    item = default;
                    return(false);
                }
            }

            RefArrayAccessUtil.SpElement(buffer, offset, default);
            this.ConsumerIndex = consumerIndex + 1; // StoreStore
            item = e;
            return(true);
        }
Exemplo n.º 3
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);