As I understand it, all three static methods in Parallel
(For
, ForEach
and Invoke
) create tasks in the background.
You can stop creating these tasks with cancel a token inside ParallelOptions
.
I made two simple examples.
In the first uses the For
method in the second Invoke
.
In the case of the For
method, the behavior is expected, after canceling the token, the creation of new tasks is stopped.
In the case of the Invoke
method, this does not happen. No matter how many methods I put in the Invoke method, they are always executed after the token is canceled. And I don't understand why this is happening.
On learn.microsoft.com in Parallel.Invoke
method
It's been said:
The cancellation token passed in with the
ParallelOptions
structure enables the caller to cancel the entire operation.
Question: Why in the case of the Invoke method, all tasks are executed and canceling the token does nothing? Or maybe I'm doing something wrong, then tell me what.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class MyClass
{
public int a = 0;
public void Add()
{
lock (this)
{
Thread.Sleep(100);
Console.WriteLine($"Do Add {DateTime.Now}, a={a}");
a++;
}
}
}
class Program
{
static void Main(string[] args)
{
void MyMethodForCancel(CancellationTokenSource cancellationTokenSource)
{
Random random = new Random();
while (true)
{
if (random.Next(1, 100) == 50)
{
cancellationTokenSource.Cancel();
Console.WriteLine($"Cancel token {DateTime.Now}");
return;
}
}
}
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.CancellationToken = cancellationTokenSource.Token;
MyClass myClass2 = new MyClass();
Action[] actions = new Action[50];
for (int i = 0; i < actions.Length; i++)
{
actions[i] = myClass2.Add;
}
Task MyTask1 = Task.Run(() => Parallel.Invoke(parallelOptions, actions));
Task MyTask2 = Task.Run(() => { Thread.Sleep(1); MyMethodForCancel(cancellationTokenSource); });
try
{
Task.WaitAll(MyTask1, MyTask2);
}
catch
{
}
Console.WriteLine($"a = {myClass2.a}"); //a = 50. Always.
}
}
}