Export (0) Print
Expand All
1 out of 2 rated this helpful - Rate this topic

How to: Stop or Break from a Parallel.For Loop

The following example shows how to break (or Exit in Visual Basic) out of a For loop, and also how to stop a loop. In this context, "break" means complete all iterations on all threads that are prior to the current iteration on the current thread, and then exit the loop. "Stop" means to stop all iterations as soon as convenient.

This example demonstrates a For loop; however, you can stop or break from a ForEach loop in the same way. In a ForEach loop, an iteration index is generated internally for each element in each partition.

using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

class Test
{
    static void Main()
    {
        StopLoop();
        BreakAtThreshold();

        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

    private static void StopLoop()
    {
        Console.WriteLine("Stop loop...");
        double[] source = MakeDemoSource(1000, 1);
        ConcurrentStack<double> results = new ConcurrentStack<double>();

        // i is the iteration variable. loopState is a  
        // compiler-generated ParallelLoopState
        Parallel.For(0, source.Length, (i, loopState) =>
        {
            // Take the first 100 values that are retrieved 
            // from anywhere in the source. 
            if (i < 100)
            {
                // Accessing shared object on each iteration 
                // is not efficient. See remarks. 
                double d = Compute(source[i]);
                results.Push(d);
            }
            else
            {
                loopState.Stop();
                return;
            }

        } // Close lambda expression.
        ); // Close Parallel.For

        Console.WriteLine("Results contains {0} elements", results.Count());
    }


    static void BreakAtThreshold()
    {
        double[] source = MakeDemoSource(10000, 1.0002);
        ConcurrentStack<double> results = new ConcurrentStack<double>();

        // Store all values below a specified threshold.
        Parallel.For(0, source.Length, (i, loopState) =>
        {
            double d = Compute(source[i]);
            results.Push(d);
            if (d > .2)
            {
                // Might be called more than once!
                loopState.Break();
                Console.WriteLine("Break called at iteration {0}. d = {1} ", i, d);
                Thread.Sleep(1000);
            }
        });

        Console.WriteLine("results contains {0} elements", results.Count());
    }

    static double Compute(double d)
    {
        //Make the processor work just a little bit. 
        return Math.Sqrt(d);
    }


    // Create a contrived array of monotonically increasing 
    // values for demonstration purposes.  
    static double[] MakeDemoSource(int size, double valToFind)
    {
        double[] result = new double[size];
        double initialval = .01;
        for (int i = 0; i < size; i++)
        {
            initialval *= valToFind;
            result[i] = initialval;
        }

        return result;
    }
}

In a Parallel.For or Parallel.ForEach loop, you cannot use the same break or Exit statement that is used in a sequential loop because those language constructs are valid for loops, and a parallel "loop" is actually a method, not a loop. Instead, you use either the Stop or Break method. Some of the overloads of Parallel.For accept an Action<int, ParallelLoopState> (Action(Of Integer, ParallelLoopState) in Visual Basic) as an input parameter. The ParallelLoopState object is created behind the scenes by the runtime, and you can give it any name you like in the lambda expression.

In the example, the StopLoop() method requires only 100 values from the source sequence, and it does not matter which elements were retrieved. In this case, the Stop method is used, because it tells all iterations of the loop, including those begun before the current iteration on other threads, to stop as soon as is convenient.

In the BreakAtThreshold() method, we retrieve all the elements up to a specified index in the source sequence. In this case, Break is called, because when we reach the index on one thread, it is possible that earlier elements in the source have not yet been processed. Break will cause other threads to abandon work on later segments (if they are engaged in any) and complete the processing of all prior elements before exiting the loop.

Note that you cannot control whether other threads on a loop continue to run after either Stop or Break is called. You can use the ParallelLoopState.IsStopped property to check whether the loop has been stopped on another thread.

  • Copy and paste the code example into a Visual Studio project.

Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft. All rights reserved.