ThrowIfCancellationRequested似乎没有抛出任何异常

时间:2014-03-20 10:56:01

标签: c# multithreading task-parallel-library task cancellationtokensource

我有以下代码:

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

list包含很少的元素。 当我按下'

时,所有Compute方法都已启动。

当我按下' c'时,不会抛出任何异常。每个Compute方法都会继续执行,直到正常结束。

当我按下“c'”时,我想停止/删除所有剩余的Compute方法。

2 个答案:

答案 0 :(得分:2)

取消并不是那样的。它不像调用Thread.Abort()来立即终止线程。

对于代码中序列中的每个元素:

  1. 调用Compute()方法
  2. 等到完成
  3. 写入控制台关于完成
  4. 检查是否已请求取消,如果是,则抛出OperationCanceledException
  5. 要取消某项任务,您需要将CancellationToken传递给被叫方法 也许,值得将长时间运行的计算作为一个循环进行组织,并检查是否在每一步都要求取消以便尽快停止它。

    例如,在您的Compute()方法中,您可以执行以下检查:

    private void Compute(CancellationToken ct)
    {
        while (true)
        {
           ComputeNextStep();
           ct.ThrowIfCancellationRequested();
        }
    }
    

答案 1 :(得分:0)

使用po.CancellationToken.IsCancellationRequested观察取消,并使用ParallelLoopState.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();