1

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();
        }
    }
Romil Kumar Jain
  • 20,239
  • 9
  • 63
  • 92
  • 3
    If someone tells you to use `Thread.Abort()`, shoo them away. – Matthew Watson Jan 22 '16 at 13:32
  • @MatthewWatson if all code of main() is running under a thread then Thread.Abort() will work. – Romil Kumar Jain Jan 22 '16 at 13:34
  • 2
    You essentially can't do this, because there's no (sane) way to interrupt some code that isn't participating in co-operative cancellation. Normally you'd let the thread continue, but stop waiting for it (and ignore its results), but it's not easy to do that with `Parallel.ForEach` – Matthew Watson Jan 22 '16 at 13:35
  • 1
    "If all code of main() is running under a thread..." But it isn't. You've just called `Parallel.ForEach()`. Anyway, [read this](http://stackoverflow.com/questions/1559255/whats-wrong-with-using-thread-abort). As Eric Lippert says there: *Thread.Abort is at best indicative of bad design, possibly unreliable, and extremely dangerous. It should be avoided at all costs* – Matthew Watson Jan 22 '16 at 13:37
  • 1
    Anyway, if you have some code that is waiting for other resources, you should change it so it allows co-operative cancellation while it is waiting. – Matthew Watson Jan 22 '16 at 13:40
  • is there any possibility for my solution? – Romil Kumar Jain Jan 22 '16 at 13:40
  • I am using IndexOf() function instead of Thread.Sleep() on big data, so it hangs some minutes also. so I just want to terminate. – Romil Kumar Jain Jan 22 '16 at 13:41
  • Then start the entire thing in a separate task that you can ignore if you want it to be cancelled. – Matthew Watson Jan 22 '16 at 13:46
  • 1
    @RomilKumarJain - What are you using `IndexOf` on that takes so long? Maybe that part of your code needs some optimization? – Enigmativity Jan 23 '16 at 05:14

1 Answers1

2

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.

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • That's good to use WaitHandle.WaitOne() instead of Thread.Sleep(). But I have to check why IndexOf() is taking so much time. I have some big data like 100KB string. – Romil Kumar Jain Jan 23 '16 at 12:40
  • 2
    The code example you provided doesn't use `IndexOf()`, so that's clearly outside the scope of the question you asked. If you have some other code that does, and you want to be able to interrupt it while it's calling `IndexOf()`, then you will need to write your own version, to which you can pass the `CancellationToken`, which it can use while it's processing to allow itself to be interrupted. – Peter Duniho Jan 23 '16 at 17:23
  • Some time IndexOf() return result in fraction of seconds and some time took more than 30 seconds. I used all combinations of IndexOf(). – Romil Kumar Jain Jan 24 '16 at 08:41
  • As your question above does not involve `IndexOf()`, discussing issues with `IndexOf()` would be outside the scope of this question. If you are having problems with that method taking too long, please post a new question, providing a good [mcve] that reliably reproduces the problem. – Peter Duniho Jan 24 '16 at 08:48
  • I am not looking for solution related to IndexOf(). I am looking for the answer of the posted question only for terminating all spawn threads from Parallel.ForEach(). – Romil Kumar Jain Jan 24 '16 at 15:44
  • _"I am not looking for solution related to IndexOf()."_ -- I guess I misunderstood the purpose in your repeated comments about `IndexOf()` then. _"I am looking for the answer of the posted question only"_ -- I have provided the answer to the question you posted. – Peter Duniho Jan 24 '16 at 18:10
  • The OP said *Thread.Sleep() is put in this code for explanation. The actual code has some code that waits for other resources.* so the question isn't actually about interrupting `Sleep()`. – Matthew Watson Jan 25 '16 at 08:56
  • @Matthew: the OP also said that the actual code "waits on resources". He hasn't bothered to post a code example that _shows_ that. I have explained to the OP that he would need to incorporate the cancellation into the waiting code, and that if he wants an answer more detailed than/different from what I've provided here, he needs to provide a code example that is actually relevant to the question he's asking. The above is the best that can be provided, given the question that was actually asked. – Peter Duniho Jan 25 '16 at 09:01