I have the following code :
CancellationTokenSource cts = new CancellationTokenSource();
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
Task.Factory.StartNew(() =>
{
if (Console.ReadKey().KeyChar == 'c')
cts.Cancel();
Console.WriteLine("press any key to exit");
});
Parallel.ForEach(list, po, (algo) =>
{
algo.Compute(); // this compute lasts 1 minute
Console.WriteLine("this job is finished");
po.CancellationToken.ThrowIfCancellationRequested();
});
The list
contains few elements.
All the Compute
methods have already been started when I press 'c'.
When I press 'c', no exception is thrown. Each Compute
methods continues its execution until its normal end.
I would like to stop/kill all the remain Compute
methods when I press 'c'.
Cancellation doesn't work like that. It's not like calling Thread.Abort()
to terminate thread immediately.
For each element in a sequence your code does:
- Calls
Compute()
method
- Waits until its completion
- Writes to console about finish
- Checks if cancellation was requested and throw the
OperationCanceledException
if it was.
In order to cancel some task you need to pass the CancellationToken
to the called method.
Perhaps, it's worth organizing your long running computations as a cycle and check if cancellation were requested at each step in order to stop it ASAP.
For example, in your Compute()
method you could perform check like this:
private void Compute(CancellationToken ct)
{
while (true)
{
ComputeNextStep();
ct.ThrowIfCancellationRequested();
}
}
Observe the cancellation with po.CancellationToken.IsCancellationRequested
and use ParallelLoopState.Stop
to stop Parallel.ForEach
:
void Compute(CancellationToken token, ParallelLoopState loopState)
{
bool more = true;
while (more)
{
if (token.IsCancellationRequested)
{
// stop Parallel.ForEach ASAP
loopState.Stop();
return;
}
// do the calc step
}
}
// ...
CancellationTokenSource cts = new CancellationTokenSource();
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
Task.Factory.StartNew(() =>
{
if (Console.ReadKey().KeyChar == 'c')
cts.Cancel();
Console.WriteLine("press any key to exit");
});
Parallel.ForEach(list, po, (algo, loopState) =>
{
algo.Compute(po.CancellationToken, loopState); // this compute lasts 1 minute
Console.WriteLine("this job is finished");
});
// observe the cancellation again and throw after Parallel.ForEach
po.CancellationToken.ThrowIfCancellationRequested();