如何立即终止Parallel.ForEach线程?

时间:2016-01-22 13:31:04

标签: c# .net multithreading parallel-processing

我在Parallel.Foreach()中调用了一些代码。代码有Thread.Sleep(60000),所以如果我也取消了令牌,那么它会在取消Parallel.ForEach循环之前等待60秒。 Thread.Sleep()放在此代码中以供解释。实际代码有一些代码等待其他资源。 我希望在调用cts.Cancel();时取消所有活动。

我也尝试过LoopState,但在我的情况下它不起作用。

 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();
        }
    }

1 个答案:

答案 0 :(得分:2)

如果我理解正确,那么你需要立即中断线程 ,而只是想让它在等待时能够中断Sleep()方法。

有许多选项,但最简单的恕我直言之一是使用CancellationToken.WaitHandle属性值,并等待而不是睡觉:

po.CancellationToken.WaitHandle.WaitOne(60000);

如果发出令牌信号,Wait()方法将在指定超时之前返回(在这种情况下为一分钟)。

通常你会检查返回值,这样你就能分辨出被发信号的句柄和等待超时之间的区别,但在你的情况下你会立即调用po.CancellationToken.ThrowIfCancellationRequested();,所以对我来说这似乎是合理的忽略Wait()方法的返回值,让下一个程序语句负责实际中断方法。