3

I have this code to start a Parallel ForEach loop:

Parallel.ForEach<ListViewItem>(filesListView.Items.Cast<ListViewItem>(), new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, item => {
    if (CallToStop == true)
        {  
            //Code here to stop the loop!
        }        
    internalProcessStart(item);
});

I have some code which will check if there is a call to stop the threads, and then I would like to break; the code, but this doesn't work with Parallel.

I found the same question by someone else, but their code is slighly different to mine, and I'm not sure where to put the ParallelLoopState state.

Thanks!

Community
  • 1
  • 1
user2924019
  • 1,983
  • 4
  • 29
  • 49

4 Answers4

6

Rewrite as below

Parallel.ForEach<ListViewItem>(filesListView.Items.Cast<ListViewItem>(), 
            new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, 
           (item, state) => {
    if (CallToStop == true)
        {  
            state.Break();
        }        
    internalProcessStart(item);
});

Hope this helps.

Liam
  • 27,717
  • 28
  • 128
  • 190
Cinchoo
  • 6,088
  • 2
  • 19
  • 34
1

I think using this overload should work:

    Parallel.ForEach<ListViewItem>(filesListView.Items.Cast<ListViewItem>(), new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, (item , state)  => 
    {
        if (/*Stop condition here*/)
        { 
            state.Break(); 
        }        
        internalProcessStart(item);
    });
YuvShap
  • 3,825
  • 2
  • 10
  • 24
1

Try using CancellationToken as in this example (MSDN).

Try something like this:

CancellationTokenSource cts = new CancellationTokenSource();

       // Use ParallelOptions instance to store the CancellationToken
        ParallelOptions po = new ParallelOptions();
        po.CancellationToken = cts.Token;
        po.MaxDegreeOfParallelism = Environment.ProcessorCount;

        try
        {
            Parallel.ForEach<ListViewItem>(filesListView.Items.Cast<ListViewItem>(), po, item => {
                // po.CancellationToken.ThrowIfCancellationRequested(); //1
                if (CallToStop == true)
                {  
                    //Code here to stop the loop!
                    cts.Cancel();
                }
                if (po.CancellationToken.IsCancellationRequested == false)
                {        
                    internalProcessStart(item);
                }
            });
        }
        catch (OperationCanceledException e)
        {
            // handle
        }
        finally
        {
            cts.Dispose();
        }

Or instead of setting CallToStop = true call cts.Cancel() directly.

Or you can uncomment //1 and let all threds that did not finished throw OperationCanceledException (only use whenyou are stopping all parallel thread because of CallToStop = true is caused by error).

You can even pass the cts.Token into your internalProcessStart(item,token) and handle what to do if you cancel when internal process is already running.

roslav
  • 470
  • 3
  • 15
1

Try something like this. Conceptually, you need to pass the loopState to your lambda function.

Parallel.ForEach<int>(new List<int>(),
            new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount },
            (val, loopState) =>
            {
                if (val == 9) //enter your stopcondition here
                {
                    loopState.Stop();
                    return;
                }
            });
Kevin Le
  • 846
  • 8
  • 17