Esempio n. 1
0
        /// <summary>
        /// Flip a phase in the <see cref="WriterReaderPhaser"/> instance, <see cref="FlipPhase(System.TimeSpan)"/> can only be called while holding the <see cref="ReaderLock()"/>.
        /// </summary>
        /// <param name="yieldPeriod">The amount of time to sleep in each yield if yield loop is needed.</param>
        /// <remarks>
        /// <seealso cref="FlipPhase(System.TimeSpan)"/> will return only after all writer critical sections (protected by <see cref="WriterCriticalSectionEnter()"/> and <see cref="WriterCriticalSectionExit(long)"/> that may have been in flight when the <see cref="FlipPhase(System.TimeSpan)"/> call were made had completed.
        /// <para>
        /// No actual writer critical section activity is required for <see cref="FlipPhase(System.TimeSpan)"/> to succeed.
        /// </para>
        /// <para>
        /// However, <see cref="FlipPhase(System.TimeSpan)"/> is lock-free with respect to calls to <see cref="WriterCriticalSectionEnter()"/> and <see cref="WriterCriticalSectionExit(long)"/>.
        /// It may spin-wait for for active writer critical section code to complete.
        /// </para>
        /// </remarks>
        public void FlipPhase(TimeSpan yieldPeriod)
        {
            if (!Monitor.IsEntered(_readerLock))
            {
                throw new InvalidOperationException("FlipPhase can only be called while holding the reader lock");
            }

            var isNextPhaseEven = (_startEpoch < 0); // Current phase is odd...

            long initialStartValue;

            // First, clear currently unused [next] phase end epoch (to proper initial value for phase):
            if (isNextPhaseEven)
            {
                initialStartValue = 0;
                WriterReaderPhaser.LazySet(ref _evenEndEpoch, initialStartValue);
            }
            else
            {
                initialStartValue = long.MinValue;
                WriterReaderPhaser.LazySet(ref _oddEndEpoch, initialStartValue);
            }

            // Next, reset start value, indicating new phase, and retain value at flip:
            //long startValueAtFlip = startEpochUpdater.getAndSet(this, initialStartValue);
            long startValueAtFlip = WriterReaderPhaser.GetAndSet(ref _startEpoch, initialStartValue);

            // Now, spin until previous phase end value catches up with start value at flip:
            bool caughtUp = false;

            do
            {
                if (isNextPhaseEven)
                {
                    caughtUp = (_oddEndEpoch == startValueAtFlip);
                }
                else
                {
                    caughtUp = (_evenEndEpoch == startValueAtFlip);
                }
                if (!caughtUp)
                {
                    //TODO: Revist this and check if a SpinWiat is actually preferable here? -LC
                    if (yieldPeriod == TimeSpan.Zero)
                    {
                        Task.Yield().GetAwaiter().GetResult();
                    }
                    else
                    {
                        //Thread.Sleep(yieldPeriod);
                        Task.Delay(yieldPeriod).GetAwaiter().GetResult();
                    }
                }
            } while (!caughtUp);
        }
Esempio n. 2
0
 /// <summary>
 /// Indicate exit from a critical section containing a write operation.
 /// </summary>
 /// <param name="criticalValueAtEnter">the opaque value (token) returned from the matching <see cref="WriterCriticalSectionEnter()"/> call.</param>
 /// <remarks>
 /// This call is wait-free on architectures that support wait free atomic increment operations, and is lock-free on architectures that do not.
 /// <para>
 /// <see cref="WriterCriticalSectionExit(long)"/> must be matched with a preceding  <see cref="WriterCriticalSectionEnter"/> call, and must be provided with the matching <see cref="WriterCriticalSectionEnter"/> call's return value, in order for CriticalSectionPhaser synchronization to function properly.
 /// </para>
 /// </remarks>
 public void WriterCriticalSectionExit(long criticalValueAtEnter)
 {
     if (criticalValueAtEnter < 0)
     {
         WriterReaderPhaser.GetAndIncrement(ref _oddEndEpoch);
     }
     else
     {
         WriterReaderPhaser.GetAndIncrement(ref _evenEndEpoch);
     }
 }
Esempio n. 3
0
 /// <summary>
 /// Indicate entry to a critical section containing a write operation.
 /// </summary>
 /// <returns>
 /// an (opaque) value associated with the critical section entry,
 /// which MUST be provided to the matching <see cref="WriterCriticalSectionExit"/> call.
 /// </returns>
 /// <remarks>
 /// <para>
 /// This call is wait-free on architectures that support wait free atomic increment operations,
 /// and is lock-free on architectures that do not.
 /// </para>
 /// <para>
 /// <see cref="WriterCriticalSectionEnter"/> must be matched with a subsequent <see cref="WriterCriticalSectionExit"/>
 /// in order for CriticalSectionPhaser synchronization to function properly.
 /// </para>
 /// <para>
 /// The <seealso cref="IDisposable"/> pattern could have been used but was not due to the high allocation count it would have incurred.
 /// </para>
 /// </remarks>
 public long WriterCriticalSectionEnter()
 {
     return(WriterReaderPhaser.GetAndIncrement(ref _startEpoch));
 }