/// <summary> /// Flip a phase in the {@link WriterReaderPhaser} instance, {@link WriterReaderPhaser#flipPhase()} /// can only be called while holding the readerLock(). /// {@link WriterReaderPhaser#flipPhase()} will return only after all writer critical sections (protected by /// {@link WriterReaderPhaser#writerCriticalSectionEnter()} ()} and /// {@link WriterReaderPhaser#writerCriticalSectionExit(long)} ()}) that may have been in flight when the /// {@link WriterReaderPhaser#flipPhase()} call were made had completed. /// No actual writer critical section activity is required for {@link WriterReaderPhaser#flipPhase()} to /// succeed. /// However, {@link WriterReaderPhaser#flipPhase()} is lock-free with respect to calls to /// {@link WriterReaderPhaser#writerCriticalSectionEnter()} and /// {@link WriterReaderPhaser#writerCriticalSectionExit(long)}. It may spin-wait for for active /// writer critical section code to complete. /// </summary> /// <param name="yieldTimeNsec">The amount of time (in nanoseconds) to sleep in each yield if yield loop is needed.</param> public void FlipPhase(long yieldTimeNsec = 0) { if (!Monitor.IsEntered(readerLockObject)) { throw new ThreadStateException("flipPhase() can only be called while holding the readerLock()"); } var nextPhaseIsEven = (startEpoch.GetValue() < 0); // Current phase is odd... long initialStartValue; // First, clear currently unused [next] phase end epoch (to proper initial value for phase): if (nextPhaseIsEven) { initialStartValue = 0; evenEndEpoch.SetValue(initialStartValue); } else { initialStartValue = long.MinValue; oddEndEpoch.SetValue(initialStartValue); } // Next, reset start value, indicating new phase, and retain value at flip: var startValueAtFlip = startEpoch.GetAndSet(initialStartValue); // Now, spin until previous phase end value catches up with start value at flip: bool caughtUp; do { if (nextPhaseIsEven) { caughtUp = (oddEndEpoch.GetValue() == startValueAtFlip); } else { caughtUp = (evenEndEpoch.GetValue() == startValueAtFlip); } if (!caughtUp) { if (yieldTimeNsec == 0) { //TODO: HdrHistogram Task.Yield(); } else { Thread.Sleep(TimeSpan.FromMilliseconds(yieldTimeNsec / 1000000.0)); } } } while (!caughtUp); }
public void Can_get_and_set() { _num.SetValue(32); _num.GetAndSet(64).Should().Be(32); _num.GetValue().Should().Be(64); }