简体   繁体   中英

How to terminate Parallel.ForEach threads immediately?

I am calling some code in Parallel.Foreach() . The code has Thread.Sleep(60000) , so if I cancel the token also then it waits for 60 seconds before cancelling the Parallel.ForEach loop. Thread.Sleep() is put in this code for explanation. The actual code has some code that waits for other resources. I want to cancel all activity as cts.Cancel(); is called.

I tried LoopState also but it will not work in my case.

 using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    class Program
    {
        static void Main()
        {
            int[] nums = Enumerable.Range(0, 10000000).ToArray();
            CancellationTokenSource cts = new CancellationTokenSource();

            // Use ParallelOptions instance to store the CancellationToken
            ParallelOptions po = new ParallelOptions();
            po.CancellationToken = cts.Token;
            po.MaxDegreeOfParallelism = System.Environment.ProcessorCount;
            Console.WriteLine("Press any key to start. Press 'c' to cancel.");
            Console.ReadKey();

            // Run a task so that we can cancel from another thread.
            Task.Factory.StartNew(() =>
            {
                if (Console.ReadKey().KeyChar == 'c')
                {
                    cts.Cancel();
                }
                Console.WriteLine("press any key to exit");
            });

            try
            {
                Parallel.ForEach(nums, po, (num) =>
                {
                    double d = Math.Sqrt(num);
                    Console.WriteLine("{0} on {1}", d, Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(60000); //Thread Sleep for 1 minute
                    po.CancellationToken.ThrowIfCancellationRequested();
                });
            }
            catch (OperationCanceledException e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                cts.Dispose();
            }

            Console.ReadKey();
        }
    }

If I understand correctly, it is not really that you need to interrupt the thread immediately , but rather that you simply want to be able to interrupt the Sleep() method while it's waiting.

There are a number of options, but one of the simplest IMHO is to use the CancellationToken.WaitHandle property value, and wait on that instead of sleeping:

po.CancellationToken.WaitHandle.WaitOne(60000);

If the token is signaled, the Wait() method will return before the timeout specified (one minute in this case).

Typically you'd check the return value, so you can tell the difference between the handle being signaled and the wait timing out, but in your case you immediately call po.CancellationToken.ThrowIfCancellationRequested(); , so it seems reasonable to me to just ignore the return value from the Wait() method and let the next program statement take care of actually interrupting the method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM