/// <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); }
/// <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); }
/// 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);