ParallelLoopState.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Threading / Tasks / ParallelLoopState.cs / 1305376 / ParallelLoopState.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// 
// ParallelState.cs 
//
// [....] 
//
// A non-generic and generic parallel state class, used by the Parallel helper class
// for parallel loop management.
// 
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
using System.Diagnostics; 
using System.Security.Permissions;
using System.Diagnostics.Contracts; 

// Prevents compiler warnings/errors regarding the use of ref params in Interlocked methods
#pragma warning disable 0420
 
namespace System.Threading.Tasks
{ 
 
    /// 
    /// Enables iterations of  loops to interact with 
    /// other iterations.
    /// 
    [HostProtection(Synchronization = true, ExternalThreading = true)]
    [DebuggerDisplay("ShouldExitCurrentIteration = {ShouldExitCurrentIteration}")] 
    public class ParallelLoopState
    { 
        // Derived classes will track a ParallelStateFlags32 or ParallelStateFlags64. 
        // So this is slightly redundant, but it enables us to implement some
        // methods in this base class. 
        private ParallelLoopStateFlags m_flagsBase;

        internal ParallelLoopState(ParallelLoopStateFlags fbase)
        { 
            m_flagsBase = fbase;
        } 
 
        /// 
        /// Internal/virtual support for ShouldExitCurrentIteration. 
        /// 
        internal virtual bool InternalShouldExitCurrentIteration
        {
            get 
            {
                Contract.Assert(false); 
                throw new NotSupportedException( 
                    Environment.GetResourceString("ParallelState_NotSupportedException_UnsupportedMethod"));
            } 
        }

        /// 
        /// Gets whether the current iteration of the loop should exit based 
        /// on requests made by this or other iterations.
        ///  
        ///  
        /// When an iteration of a loop calls  or , or
        /// when one throws an exception, or when the loop is canceled, the  class will proactively 
        /// attempt to prohibit additional iterations of the loop from starting execution.
        /// However, there may be cases where it is unable to prevent additional iterations from starting.
        /// It may also be the case that a long-running iteration has already begun execution.  In such
        /// cases, iterations may explicitly check the  property and 
        /// cease execution if the property returns true.
        ///  
        public bool ShouldExitCurrentIteration 
        {
            get 
            {
                return InternalShouldExitCurrentIteration;
            }
        } 

        ///  
        /// Gets whether any iteration of the loop has called . 
        /// 
        public bool IsStopped 
        {
            get
            {
                return ((m_flagsBase.LoopStateFlags & ParallelLoopStateFlags.PLS_STOPPED) != 0); 
            }
        } 
 
        /// 
        /// Gets whether any iteration of the loop has thrown an exception that went unhandled by that 
        /// iteration.
        /// 
        public bool IsExceptional
        { 
            get
            { 
                return ((m_flagsBase.LoopStateFlags & ParallelLoopStateFlags.PLS_EXCEPTIONAL) != 0); 
            }
        } 

        /// 
        /// Internal/virtual support for LowestBreakIteration.
        ///  
        internal virtual long? InternalLowestBreakIteration
        { 
            get 
            {
                Contract.Assert(false); 
                throw new NotSupportedException(
                    Environment.GetResourceString("ParallelState_NotSupportedException_UnsupportedMethod"));
            }
        } 

        ///  
        /// Gets the lowest iteration of the loop from which  was called. 
        /// 
        ///  
        /// If no iteration of the loop called , this property will return null.
        /// 
        public long? LowestBreakIteration
        { 
            get
            { 
                return InternalLowestBreakIteration; 
            }
        } 

        /// 
        /// Communicates that the  loop should cease execution at the system's earliest
        /// convenience. 
        /// 
        ///  
        /// The  method was previously called.   and  may not be used in combination by iterations of the same loop.
        ///  
        /// 
        /// 
        ///  may be used to communicate to the loop that no other iterations need be run.
        /// For long-running iterations that may already be executing,  causes  
        /// to return true for all other iterations of the loop, such that another iteration may check  and exit early if it's observed to be true. 
        ///  
        /// 
        ///  is typically employed in search-based algorithms, where once a result is found, 
        /// no other iterations need be executed.
        /// 
        /// 
        public void Stop() 
        {
            m_flagsBase.Stop(); 
        } 

        // Internal/virtual support for Break(). 
        internal virtual void InternalBreak()
        {
            Contract.Assert(false);
            throw new NotSupportedException( 
                    Environment.GetResourceString("ParallelState_NotSupportedException_UnsupportedMethod"));
        } 
 
        /// 
        /// Communicates that the  loop should cease execution at the system's earliest 
        /// convenience of iterations beyond the current iteration.
        /// 
        /// 
        /// The  method was previously called.  and  
        /// may not be used in combination by iterations of the same loop.
        ///  
        ///  
        /// 
        ///  may be used to communicate to the loop that no other iterations after the 
        /// current iteration need be run. For example, if  is called from the 100th
        /// iteration of a for loop iterating in parallel from 0 to 1000, all iterations less than 100 should
        /// still be run, but the iterations from 101 through to 1000 are not necessary.
        ///  
        /// 
        /// For long-running iterations that may already be executing,  causes  
        /// to be set to the current iteration's index if the current index is less than the current value of
        /// . 
        /// 
        /// 
        ///  is typically employed in search-based algorithms where an ordering is
        /// present in the data source. 
        /// 
        ///  
        public void Break() 
        {
            InternalBreak(); 
        }

        // Helper method to avoid repeating Break() logic between ParallelState32 and ParallelState32
        internal static void Break(int iteration, ParallelLoopStateFlags32 pflags) 
        {
            int oldValue = ParallelLoopStateFlags.PLS_NONE; 
 
            // Attempt to change state from "not stopped or broken or canceled or exceptional" to "broken".
            if (!pflags.AtomicLoopStateUpdate(ParallelLoopStateFlags.PLS_BROKEN, 
                                             ParallelLoopStateFlags.PLS_STOPPED | ParallelLoopStateFlags.PLS_EXCEPTIONAL | ParallelLoopStateFlags.PLS_CANCELED,
                                             ref oldValue))
            {
 
                // If we were already stopped, we have a problem
                if ((oldValue & ParallelLoopStateFlags.PLS_STOPPED) != 0) 
                { 
                    throw new InvalidOperationException(
                        Environment.GetResourceString("ParallelState_Break_InvalidOperationException_BreakAfterStop")); 
                }
                else
                {
                    // Apparently we previously got cancelled or became exceptional. No action necessary 
                    return;
                } 
            } 

            // replace shared LowestBreakIteration with CurrentIteration, but only if CurrentIteration 
            // is less than LowestBreakIteration.
            int oldLBI = pflags.m_lowestBreakIteration;
            if (iteration < oldLBI)
            { 
                SpinWait wait = new SpinWait();
                while (Interlocked.CompareExchange( 
                    ref pflags.m_lowestBreakIteration, 
                        iteration,
                        oldLBI) != oldLBI) 
                {
                    wait.SpinOnce();
                    oldLBI = pflags.m_lowestBreakIteration;
                    if (iteration > oldLBI) break; 
                }
            } 
 
        }
 
        // Helper method to avoid repeating Break() logic between ParallelState64 and ParallelState64
        internal static void Break(long iteration, ParallelLoopStateFlags64 pflags)
        {
            int oldValue = ParallelLoopStateFlags.PLS_NONE; 

            // Attempt to change state from "not stopped or broken or canceled or exceptional" to "broken". 
            if (!pflags.AtomicLoopStateUpdate(ParallelLoopStateFlags.PLS_BROKEN, 
                                             ParallelLoopStateFlags.PLS_STOPPED | ParallelLoopStateFlags.PLS_EXCEPTIONAL | ParallelLoopStateFlags.PLS_CANCELED,
                                             ref oldValue)) 
            {

                // If we were already stopped, we have a problem
                if ((oldValue & ParallelLoopStateFlags.PLS_STOPPED) != 0) 
                {
                    throw new InvalidOperationException( 
                        Environment.GetResourceString("ParallelState_Break_InvalidOperationException_BreakAfterStop")); 
                }
                else 
                {
                    // Apparently we previously got cancelled or became exceptional. No action necessary
                    return;
                } 
            }
 
            // replace shared LowestBreakIteration with CurrentIteration, but only if CurrentIteration 
            // is less than LowestBreakIteration.
            long oldLBI = pflags.LowestBreakIteration; 
            if (iteration < oldLBI)
            {
                SpinWait wait = new SpinWait();
                while (Interlocked.CompareExchange( 
                    ref pflags.m_lowestBreakIteration,
                        iteration, 
                        oldLBI) != oldLBI) 
                {
                    wait.SpinOnce(); 
                    oldLBI = pflags.LowestBreakIteration;
                    if (iteration > oldLBI) break;
                }
            } 

        } 
    } 

    internal class ParallelLoopState32 : ParallelLoopState 
    {
        private ParallelLoopStateFlags32 m_sharedParallelStateFlags;
        private int m_currentIteration = 0;
 
        /// 
        /// Internal constructor to ensure an instance isn't created by users. 
        ///  
        /// A flag shared among all threads participating
        /// in the execution of a certain loop. 
        internal ParallelLoopState32(ParallelLoopStateFlags32 sharedParallelStateFlags)
            : base(sharedParallelStateFlags)
        {
            m_sharedParallelStateFlags = sharedParallelStateFlags; 
        }
 
        ///  
        /// Tracks the current loop iteration for the owning task.
        /// This is used to compute whether or not the task should 
        /// terminate early due to a Break() call.
        /// 
        internal int CurrentIteration {
            get { return m_currentIteration; } 
            set { m_currentIteration = value; }
        } 
 
        /// 
        /// Returns true if we should be exiting from the current iteration 
        /// due to Stop(), Break() or exception.
        /// 
        internal override bool InternalShouldExitCurrentIteration
        { 
            get { return m_sharedParallelStateFlags.ShouldExitLoop(CurrentIteration); }
        } 
 
        /// 
        /// Returns the lowest iteration at which Break() has been called, or 
        /// null if Break() has not yet been called.
        /// 
        internal override long? InternalLowestBreakIteration
        { 
            get {return m_sharedParallelStateFlags.NullableLowestBreakIteration; }
        } 
 
        /// 
        /// Communicates that parallel tasks should stop when they reach a specified iteration element. 
        /// (which is CurrentIteration of the caller).
        /// 
        /// Break() called after Stop().
        ///  
        /// This is shared with all other concurrent threads in the system which are participating in the
        /// loop's execution. After calling Break(), no additional iterations will be executed on 
        /// the current thread, and other worker threads will execute once they get beyond the calling iteration. 
        /// 
        internal override void InternalBreak() 
        {
            ParallelLoopState.Break(CurrentIteration, m_sharedParallelStateFlags);
        }
    } 

    ///  
    /// Allows independent iterations of a parallel loop to interact with other iterations. 
    /// 
    internal class ParallelLoopState64 : ParallelLoopState 
    {
        private ParallelLoopStateFlags64 m_sharedParallelStateFlags;
        private long m_currentIteration = 0;
 
        /// 
        /// Internal constructor to ensure an instance isn't created by users. 
        ///  
        /// A flag shared among all threads participating
        /// in the execution of a certain loop. 
        internal ParallelLoopState64(ParallelLoopStateFlags64 sharedParallelStateFlags)
            : base(sharedParallelStateFlags)
        {
            m_sharedParallelStateFlags = sharedParallelStateFlags; 
        }
 
        ///  
        /// Tracks the current loop iteration for the owning task.
        /// This is used to compute whether or not the task should 
        /// terminate early due to a Break() call.
        /// 
        internal long CurrentIteration
        { 
            // No interlocks needed, because this value is only accessed in a single thread.
            get {return m_currentIteration;} 
            set {m_currentIteration = value; } 
        }
 
        /// 
        /// Returns true if we should be exiting from the current iteration
        /// due to Stop(), Break() or exception.
        ///  
        internal override bool InternalShouldExitCurrentIteration
        { 
            get { return m_sharedParallelStateFlags.ShouldExitLoop(CurrentIteration); } 
        }
 
        /// 
        /// Returns the lowest iteration at which Break() has been called, or
        /// null if Break() has not yet been called.
        ///  
        internal override long? InternalLowestBreakIteration
        { 
            // We don't need to worry about torn read/write here because 
            // ParallelStateFlags64.LowestBreakIteration property is protected
            // by an Interlocked.Read(). 
            get { return m_sharedParallelStateFlags.NullableLowestBreakIteration; }
        }

        ///  
        /// Communicates that parallel tasks should stop when they reach a specified iteration element.
        /// (which is CurrentIteration of the caller). 
        ///  
        /// Break() called after Stop().
        ///  
        /// Atomically sets shared StoppedBroken flag to BROKEN, then atomically sets shared
        /// LowestBreakIteration to CurrentIteration, but only if CurrentIteration is less than
        /// LowestBreakIteration.
        ///  
        internal override void InternalBreak()
        { 
            ParallelLoopState.Break(CurrentIteration, m_sharedParallelStateFlags); 
        }
 
    }

    /// 
    /// State information that is common between ParallelStateFlags class 
    /// and ParallelStateFlags64 class.
    ///  
    internal class ParallelLoopStateFlags 
    {
        internal static int PLS_NONE; 
        internal static int PLS_EXCEPTIONAL = 1;
        internal static int PLS_BROKEN = 2;
        internal static int PLS_STOPPED = 4;
        internal static int PLS_CANCELED = 8; 

        private volatile int m_LoopStateFlags = PLS_NONE; 
 
        internal int LoopStateFlags
        { 
            get { return m_LoopStateFlags; }
        }

        internal bool AtomicLoopStateUpdate(int newState, int illegalStates) 
        {
            int oldState = 0; 
            return AtomicLoopStateUpdate(newState, illegalStates, ref oldState); 
        }
 
        internal bool AtomicLoopStateUpdate(int newState, int illegalStates, ref int oldState)
        {
            SpinWait sw = new SpinWait();
 
            do
            { 
                oldState = m_LoopStateFlags; 
                if ((oldState & illegalStates) != 0) return false;
                if (Interlocked.CompareExchange(ref m_LoopStateFlags, oldState | newState, oldState) == oldState) 
                {
                    return true;
                }
                sw.SpinOnce(); 
            } while (true);
 
        } 

        internal void SetExceptional() 
        {
            // we can set the exceptional flag regardless of the state of other bits.
            AtomicLoopStateUpdate(PLS_EXCEPTIONAL, PLS_NONE);
        } 

        internal void Stop() 
        { 
            // disallow setting of PLS_STOPPED bit only if PLS_BROKEN was already set
            if (!AtomicLoopStateUpdate(PLS_STOPPED, PLS_BROKEN)) 
            {
                throw new InvalidOperationException(
    Environment.GetResourceString("ParallelState_Stop_InvalidOperationException_StopAfterBreak"));
            } 
        }
 
        // Returns true if StoppedBroken is updated to PLS_CANCELED. 
        internal bool Cancel()
        { 
            // we can set the canceled flag regardless of the state of other bits.
            return (AtomicLoopStateUpdate(PLS_CANCELED, PLS_NONE));
        }
    } 

    ///  
    /// An internal class used to share accounting information in 32-bit versions 
    /// of For()/ForEach() loops.
    ///  
    internal class ParallelLoopStateFlags32 : ParallelLoopStateFlags
    {
        // Records the lowest iteration at which a Break() has been called,
        // or Int32.MaxValue if no break has been called.  Used directly 
        // by Break().
        internal volatile int m_lowestBreakIteration = Int32.MaxValue; 
 
        // Not strictly necessary, but maintains consistency with ParallelStateFlags64
        internal int LowestBreakIteration 
        {
            get { return m_lowestBreakIteration; }
        }
 
        // Does some processing to convert m_lowestBreakIteration to a long?.
        internal long? NullableLowestBreakIteration 
        { 
            get
            { 
                if (m_lowestBreakIteration == Int32.MaxValue) return null;
                else
                {
                    // protect against torn read of 64-bit value 
                    long rval = m_lowestBreakIteration;
                    if (IntPtr.Size >= 8) return rval; 
                    else return Interlocked.Read(ref rval); 
                }
            } 
        }


        ///  
        /// Lets the caller know whether or not to prematurely exit the For/ForEach loop.
        /// If this returns true, then exit the loop.  Otherwise, keep going. 
        ///  
        /// The caller's current iteration point
        /// in the loop. 
        /// 
        /// The loop should exit on any one of the following conditions:
        ///   (1) Stop() has been called by one or more tasks.
        ///   (2) An exception has been raised by one or more tasks. 
        ///   (3) Break() has been called by one or more tasks, and
        ///       CallerIteration exceeds the (lowest) iteration at which 
        ///       Break() was called. 
        ///   (4) The loop was canceled.
        ///  
        internal bool ShouldExitLoop(int CallerIteration)
        {
            int flags = LoopStateFlags;
            return (flags != PLS_NONE && ( 
                            ((flags & (PLS_EXCEPTIONAL | PLS_STOPPED | PLS_CANCELED)) != 0) ||
                            (((flags & PLS_BROKEN) != 0) && (CallerIteration > LowestBreakIteration)))); 
        } 

        // This lighter version of ShouldExitLoop will be used when the body type doesn't contain a state. 
        // Since simpler bodies cannot stop or break, we can safely skip checks for those flags here.
        internal bool ShouldExitLoop()
        {
            int flags = LoopStateFlags; 
            return ((flags != PLS_NONE) && ((flags & (PLS_EXCEPTIONAL | PLS_CANCELED)) != 0));
        } 
    } 

    ///  
    /// An internal class used to share accounting information in 64-bit versions
    /// of For()/ForEach() loops.
    /// 
    internal class ParallelLoopStateFlags64 : ParallelLoopStateFlags 
    {
        // Records the lowest iteration at which a Break() has been called, 
        // or Int64.MaxValue if no break has been called.  Used directly 
        // by Break().
        internal long m_lowestBreakIteration = Int64.MaxValue; 

        // Performs a conditionally interlocked read of m_lowestBreakIteration.
        internal long LowestBreakIteration
        { 
            get
            { 
                if (IntPtr.Size >= 8) return m_lowestBreakIteration; 
                else return Interlocked.Read(ref m_lowestBreakIteration);
            } 
        }

        // Does some processing to convert m_lowestBreakIteration to a long?.
        internal long? NullableLowestBreakIteration 
        {
            get 
            { 
                if (m_lowestBreakIteration == Int64.MaxValue) return null;
                else 
                {
                    if (IntPtr.Size >= 8) return m_lowestBreakIteration;
                    else return Interlocked.Read(ref m_lowestBreakIteration);
                } 
            }
        } 
 
        /// 
        /// Lets the caller know whether or not to prematurely exit the For/ForEach loop. 
        /// If this returns true, then exit the loop.  Otherwise, keep going.
        /// 
        /// The caller's current iteration point
        /// in the loop. 
        /// 
        /// The loop should exit on any one of the following conditions: 
        ///   (1) Stop() has been called by one or more tasks. 
        ///   (2) An exception has been raised by one or more tasks.
        ///   (3) Break() has been called by one or more tasks, and 
        ///       CallerIteration exceeds the (lowest) iteration at which
        ///       Break() was called.
        ///   (4) The loop has been canceled.
        ///  
        internal bool ShouldExitLoop(long CallerIteration)
        { 
            int flags = LoopStateFlags; 
            return (flags != PLS_NONE && (
                            ((flags & (PLS_EXCEPTIONAL | PLS_STOPPED | PLS_CANCELED)) != 0) || 
                            (((flags & PLS_BROKEN) != 0) && (CallerIteration > LowestBreakIteration))));
        }

        // This lighter version of ShouldExitLoop will be used when the body type doesn't contain a state. 
        // Since simpler bodies cannot stop or break, we can safely skip checks for those flags here.
        internal bool ShouldExitLoop() 
        { 
            int flags = LoopStateFlags;
            return ((flags != PLS_NONE) && ((flags & (PLS_EXCEPTIONAL | PLS_CANCELED)) != 0)); 
        }
    }

    ///  
    /// Provides completion status on the execution of a  loop.
    ///  
    ///  
    /// If  returns true, then the loop ran to completion, such that all iterations
    /// of the loop were executed. If  returns false and  returns null, a call to  was used to end the loop prematurely. If  returns false and  returns a non-null integral
    /// value,  was used to end the loop prematurely. 
    /// 
    public struct ParallelLoopResult 
    { 
        internal bool m_completed;
        internal long? m_lowestBreakIteration; 

        /// 
        /// Gets whether the loop ran to completion, such that all iterations of the loop were executed
        /// and the loop didn't receive a request to end prematurely. 
        /// 
        public bool IsCompleted { get { return m_completed; } } 
 
        /// 
        /// Gets the index of the lowest iteration from which 
        /// was called.
        /// 
        ///  
        /// If  was not employed, this property will
        /// return null. 
        ///  
        public long? LowestBreakIteration { get { return m_lowestBreakIteration; } }
    } 

}

#pragma warning restore 0420 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK