summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Threading/Tasks/ParallelLoopState.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Threading/Tasks/ParallelLoopState.cs')
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/ParallelLoopState.cs641
1 files changed, 0 insertions, 641 deletions
diff --git a/src/mscorlib/src/System/Threading/Tasks/ParallelLoopState.cs b/src/mscorlib/src/System/Threading/Tasks/ParallelLoopState.cs
deleted file mode 100644
index 6a62cf8977..0000000000
--- a/src/mscorlib/src/System/Threading/Tasks/ParallelLoopState.cs
+++ /dev/null
@@ -1,641 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-// 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
-{
-
- /// <summary>
- /// Enables iterations of <see cref="T:System.Threading.Tasks.Parallel"/> loops to interact with
- /// other iterations.
- /// </summary>
- [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;
- }
-
- /// <summary>
- /// Internal/virtual support for ShouldExitCurrentIteration.
- /// </summary>
- internal virtual bool InternalShouldExitCurrentIteration
- {
- get
- {
- Debug.Assert(false);
- throw new NotSupportedException(
- Environment.GetResourceString("ParallelState_NotSupportedException_UnsupportedMethod"));
- }
- }
-
- /// <summary>
- /// Gets whether the current iteration of the loop should exit based
- /// on requests made by this or other iterations.
- /// </summary>
- /// <remarks>
- /// When an iteration of a loop calls <see cref="Break()"/> or <see cref="Stop()"/>, or
- /// when one throws an exception, or when the loop is canceled, the <see cref="Parallel"/> 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 <see cref="ShouldExitCurrentIteration"/> property and
- /// cease execution if the property returns true.
- /// </remarks>
- public bool ShouldExitCurrentIteration
- {
- get
- {
- return InternalShouldExitCurrentIteration;
- }
- }
-
- /// <summary>
- /// Gets whether any iteration of the loop has called <see cref="Stop()"/>.
- /// </summary>
- public bool IsStopped
- {
- get
- {
- return ((m_flagsBase.LoopStateFlags & ParallelLoopStateFlags.PLS_STOPPED) != 0);
- }
- }
-
- /// <summary>
- /// Gets whether any iteration of the loop has thrown an exception that went unhandled by that
- /// iteration.
- /// </summary>
- public bool IsExceptional
- {
- get
- {
- return ((m_flagsBase.LoopStateFlags & ParallelLoopStateFlags.PLS_EXCEPTIONAL) != 0);
- }
- }
-
- /// <summary>
- /// Internal/virtual support for LowestBreakIteration.
- /// </summary>
- internal virtual long? InternalLowestBreakIteration
- {
- get
- {
- Debug.Assert(false);
- throw new NotSupportedException(
- Environment.GetResourceString("ParallelState_NotSupportedException_UnsupportedMethod"));
- }
- }
-
- /// <summary>
- /// Gets the lowest iteration of the loop from which <see cref="Break()"/> was called.
- /// </summary>
- /// <remarks>
- /// If no iteration of the loop called <see cref="Break()"/>, this property will return null.
- /// </remarks>
- public long? LowestBreakIteration
- {
- get
- {
- return InternalLowestBreakIteration;
- }
- }
-
- /// <summary>
- /// Communicates that the <see cref="Parallel"/> loop should cease execution at the system's earliest
- /// convenience.
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">
- /// The <see cref="Break()"/> method was previously called. <see cref="Break()"/> and <see
- /// cref="Stop()"/> may not be used in combination by iterations of the same loop.
- /// </exception>
- /// <remarks>
- /// <para>
- /// <see cref="Stop()"/> may be used to communicate to the loop that no other iterations need be run.
- /// For long-running iterations that may already be executing, <see cref="Stop()"/> causes <see cref="IsStopped"/>
- /// to return true for all other iterations of the loop, such that another iteration may check <see
- /// cref="IsStopped"/> and exit early if it's observed to be true.
- /// </para>
- /// <para>
- /// <see cref="Stop()"/> is typically employed in search-based algorithms, where once a result is found,
- /// no other iterations need be executed.
- /// </para>
- /// </remarks>
- public void Stop()
- {
- m_flagsBase.Stop();
- }
-
- // Internal/virtual support for Break().
- internal virtual void InternalBreak()
- {
- Debug.Assert(false);
- throw new NotSupportedException(
- Environment.GetResourceString("ParallelState_NotSupportedException_UnsupportedMethod"));
- }
-
- /// <summary>
- /// Communicates that the <see cref="Parallel"/> loop should cease execution at the system's earliest
- /// convenience of iterations beyond the current iteration.
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">
- /// The <see cref="Stop()"/> method was previously called. <see cref="Break()"/> and <see cref="Stop()"/>
- /// may not be used in combination by iterations of the same loop.
- /// </exception>
- /// <remarks>
- /// <para>
- /// <see cref="Break()"/> may be used to communicate to the loop that no other iterations after the
- /// current iteration need be run. For example, if <see cref="Break()"/> 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.
- /// </para>
- /// <para>
- /// For long-running iterations that may already be executing, <see cref="Break()"/> causes <see
- /// cref="LowestBreakIteration"/>
- /// to be set to the current iteration's index if the current index is less than the current value of
- /// <see cref="LowestBreakIteration"/>.
- /// </para>
- /// <para>
- /// <see cref="Break()"/> is typically employed in search-based algorithms where an ordering is
- /// present in the data source.
- /// </para>
- /// </remarks>
- public void Break()
- {
- InternalBreak();
- }
-
- // Helper method to avoid repeating Break() logic between ParallelState32 and ParallelState32<TLocal>
- 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<TLocal>
- 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;
-
- /// <summary>
- /// Internal constructor to ensure an instance isn't created by users.
- /// </summary>
- /// <param name="sharedParallelStateFlags">A flag shared among all threads participating
- /// in the execution of a certain loop.</param>
- internal ParallelLoopState32(ParallelLoopStateFlags32 sharedParallelStateFlags)
- : base(sharedParallelStateFlags)
- {
- m_sharedParallelStateFlags = sharedParallelStateFlags;
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- internal int CurrentIteration {
- get { return m_currentIteration; }
- set { m_currentIteration = value; }
- }
-
- /// <summary>
- /// Returns true if we should be exiting from the current iteration
- /// due to Stop(), Break() or exception.
- /// </summary>
- internal override bool InternalShouldExitCurrentIteration
- {
- get { return m_sharedParallelStateFlags.ShouldExitLoop(CurrentIteration); }
- }
-
- /// <summary>
- /// Returns the lowest iteration at which Break() has been called, or
- /// null if Break() has not yet been called.
- /// </summary>
- internal override long? InternalLowestBreakIteration
- {
- get {return m_sharedParallelStateFlags.NullableLowestBreakIteration; }
- }
-
- /// <summary>
- /// Communicates that parallel tasks should stop when they reach a specified iteration element.
- /// (which is CurrentIteration of the caller).
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">Break() called after Stop().</exception>
- /// <remarks>
- /// 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.
- /// </remarks>
- internal override void InternalBreak()
- {
- ParallelLoopState.Break(CurrentIteration, m_sharedParallelStateFlags);
- }
- }
-
- /// <summary>
- /// Allows independent iterations of a parallel loop to interact with other iterations.
- /// </summary>
- internal class ParallelLoopState64 : ParallelLoopState
- {
- private ParallelLoopStateFlags64 m_sharedParallelStateFlags;
- private long m_currentIteration = 0;
-
- /// <summary>
- /// Internal constructor to ensure an instance isn't created by users.
- /// </summary>
- /// <param name="sharedParallelStateFlags">A flag shared among all threads participating
- /// in the execution of a certain loop.</param>
- internal ParallelLoopState64(ParallelLoopStateFlags64 sharedParallelStateFlags)
- : base(sharedParallelStateFlags)
- {
- m_sharedParallelStateFlags = sharedParallelStateFlags;
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- internal long CurrentIteration
- {
- // No interlocks needed, because this value is only accessed in a single thread.
- get {return m_currentIteration;}
- set {m_currentIteration = value; }
- }
-
- /// <summary>
- /// Returns true if we should be exiting from the current iteration
- /// due to Stop(), Break() or exception.
- /// </summary>
- internal override bool InternalShouldExitCurrentIteration
- {
- get { return m_sharedParallelStateFlags.ShouldExitLoop(CurrentIteration); }
- }
-
- /// <summary>
- /// Returns the lowest iteration at which Break() has been called, or
- /// null if Break() has not yet been called.
- /// </summary>
- 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; }
- }
-
- /// <summary>
- /// Communicates that parallel tasks should stop when they reach a specified iteration element.
- /// (which is CurrentIteration of the caller).
- /// </summary>
- /// <exception cref="T:System.InvalidOperationException">Break() called after Stop().</exception>
- /// <remarks>
- /// Atomically sets shared StoppedBroken flag to BROKEN, then atomically sets shared
- /// LowestBreakIteration to CurrentIteration, but only if CurrentIteration is less than
- /// LowestBreakIteration.
- /// </remarks>
- internal override void InternalBreak()
- {
- ParallelLoopState.Break(CurrentIteration, m_sharedParallelStateFlags);
- }
-
- }
-
- /// <summary>
- /// State information that is common between ParallelStateFlags class
- /// and ParallelStateFlags64 class.
- /// </summary>
- 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));
- }
- }
-
- /// <summary>
- /// An internal class used to share accounting information in 32-bit versions
- /// of For()/ForEach() loops.
- /// </summary>
- 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);
- }
- }
- }
-
-
- /// <summary>
- /// 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.
- /// </summary>
- /// <param name="CallerIteration">The caller's current iteration point
- /// in the loop.</param>
- /// <remarks>
- /// 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.
- /// </remarks>
- 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));
- }
- }
-
- /// <summary>
- /// An internal class used to share accounting information in 64-bit versions
- /// of For()/ForEach() loops.
- /// </summary>
- 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);
- }
- }
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- /// <param name="CallerIteration">The caller's current iteration point
- /// in the loop.</param>
- /// <remarks>
- /// 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.
- /// </remarks>
- 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));
- }
- }
-
- /// <summary>
- /// Provides completion status on the execution of a <see cref="Parallel"/> loop.
- /// </summary>
- /// <remarks>
- /// If <see cref="IsCompleted"/> returns true, then the loop ran to completion, such that all iterations
- /// of the loop were executed. If <see cref="IsCompleted"/> returns false and <see
- /// cref="LowestBreakIteration"/> returns null, a call to <see
- /// cref="System.Threading.Tasks.ParallelLoopState.Stop"/> was used to end the loop prematurely. If <see
- /// cref="IsCompleted"/> returns false and <see cref="LowestBreakIteration"/> returns a non-null integral
- /// value, <see cref="System.Threading.Tasks.ParallelLoopState.Break()"/> was used to end the loop prematurely.
- /// </remarks>
- public struct ParallelLoopResult
- {
- internal bool m_completed;
- internal long? m_lowestBreakIteration;
-
- /// <summary>
- /// 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.
- /// </summary>
- public bool IsCompleted { get { return m_completed; } }
-
- /// <summary>
- /// Gets the index of the lowest iteration from which <see
- /// cref="System.Threading.Tasks.ParallelLoopState.Break()"/>
- /// was called.
- /// </summary>
- /// <remarks>
- /// If <see cref="System.Threading.Tasks.ParallelLoopState.Break()"/> was not employed, this property will
- /// return null.
- /// </remarks>
- public long? LowestBreakIteration { get { return m_lowestBreakIteration; } }
- }
-
-}
-
-#pragma warning restore 0420