Reputation: 2057
From Microsoft documentation, I have this piece of code. But it doesn't work as intended. The loop stops without hiting the cancellation key when it's finish. No key press or console.write in the new task is displayed.
Console ouput, debug trace explainned:
Press any key to start. Press 'c' to cancel. <-- Starting
. <-- Key pressed
<Multiple line of result> <-- Parallel.ForEach ouput
(...)
</Multiple line of result>
Canceled <-- Hit finally Parallel.ForEach over
END! Press a key <-- Program
What I expected was: Starting a thread waiting for a specific key. If anything else than this specific key is hit, prompt for specific.
What I did:
static void Main(string[] args)
{
test();
}
static void test()
{
int[] nums = Enumerable.Range(0, 1000).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;
po.CancellationToken.ThrowIfCancellationRequested();
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(() =>
{
while (Console.KeyAvailable)
{
if (Console.ReadKey().KeyChar == 'c')
{
Console.WriteLine("Cancellation..");
cts.Cancel();
}
Console.WriteLine("\nPress 'c' to cancel.");
}
Console.WriteLine("task ..");
});
try
{
Parallel.ForEach(nums, po, (num) =>
{
double d = Math.Sqrt(num);
Console.WriteLine("{0} on {1}", d, Thread.CurrentThread.ManagedThreadId);
});
}
catch (OperationCanceledException e)
{
Console.WriteLine(e.Message);
}
catch (Exception e)
{ // perhaps an exception that was not expected?
Console.WriteLine(e.Message);
}
finally
{
cts.Dispose();
Console.WriteLine("Canceled");
}
Console.WriteLine("END! Press a key");
Console.ReadKey();
}
99% msdn code, minor edit for trace, trying to debug.
Upvotes: 1
Views: 257
Reputation: 17658
You are missing a in line, it's in the MSDN code:
Parallel.ForEach(nums, po, (num) =>
{
//add this one, it is to cancel it.
//UPDATE: this isn't actually needed
//po.CancellationToken.ThrowIfCancellationRequested();
});
And, your while loop exits prematurely. You should remove the Console.KeyAvailable
line.
Also note that the Console.ReadKey()
is blocking the loop.
Task.Factory.StartNew(() =>
{
Console.WriteLine("\nPress 'c' to cancel.");
if (Console.ReadKey().KeyChar == 'c')
{
Console.WriteLine("Cancellation..");
cts.Cancel();
}
});
As alternative, if you want the same flow, you could use:
while (!Console.KeyAvailable)
In that case, taken from this msdn example, it should be like:
while (Console.KeyAvailable == false)
Thread.Sleep(250); // Loop until input is entered.
cki = Console.ReadKey(true);
Console.WriteLine("You pressed the '{0}' key.", cki.Key);
Note: the Sleep
is there to not overload your CPU.
Full working code: (note: no sleep applied and the Press 'c' to cancel
isn't displayed in in such a way that you can actually see it, IMO you should just leave out the while (!Console.KeyAvailable)
part.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp15
{
class Program
{
static void Main(string[] args)
{
test();
}
static void test()
{
int[] nums = Enumerable.Range(0, 10000).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;
po.CancellationToken.ThrowIfCancellationRequested();
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(() =>
{
while (true)
{
while (!Console.KeyAvailable)
{
Console.WriteLine("\nPress 'c' to cancel.");
}
if (Console.ReadKey().KeyChar == 'c')
{
Console.WriteLine("Cancellation..");
cts.Cancel();
break;
}
}
Console.WriteLine("task ..");
});
try
{
Parallel.ForEach(nums, po, (num) =>
{
double d = Math.Sqrt(num);
Console.WriteLine("{0} on {1}", d, Thread.CurrentThread.ManagedThreadId);
po.CancellationToken.ThrowIfCancellationRequested();
});
}
catch (OperationCanceledException e)
{
Console.WriteLine(e.Message);
}
catch (Exception e)
{ // perhaps an exception that was not expected?
Console.WriteLine(e.Message);
}
finally
{
cts.Dispose();
Console.WriteLine("Canceled");
}
Console.WriteLine("END! Press a key");
Console.ReadKey();
}
}
}
Upvotes: 1