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