C# 通过取消安装请求不';我似乎没有任何例外

C# 通过取消安装请求不';我似乎没有任何例外,c#,multithreading,task-parallel-library,task,cancellationtokensource,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();

我有以下代码:

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();
 });
列表
包含的元素很少。 当我按下“c”键时,所有的
Compute
方法都已启动

当我按下“c”键时,不会引发异常。每个
Compute
方法继续执行,直到其正常结束


当我按下“c”键时,我想停止/杀死所有剩余的
计算方法。

取消不是这样工作的。这不像调用
Thread.Abort()
立即终止线程

对于序列中的每个元素,您的代码执行以下操作:

  • 调用
    Compute()
    方法
  • 等待它完成
  • 向控制台写入关于完成的信息
  • 检查是否请求取消,如果请求取消,则抛出
    OperationCanceledException
  • 为了取消某些任务,您需要将
    CancellationToken
    传递给被调用的方法。
    也许,将长时间运行的计算组织为一个循环,并检查是否在每个步骤都请求取消以尽快停止它是值得的

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

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

    使用
    po.CancellationToken.IsCancellationRequested查看取消操作,并使用停止
    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();
    

    我认为您需要手动处理
    工作单元
    方法中的取消`一旦线程启动,它将自行处理。你需要从线程中抛出它。是的,你必须将取消令牌传递给
    algo.Compute()
    ,并在该方法的循环中检查它。只需将magic
    ThrowIfCancellationRequested
    行放在源代码中的某个地方,就不会发生任何事情。这一行也需要执行。我要补充一点,
    CancellationToken`的点是为新线程播种的进程和线程本身之间的连接线程(双关语)。如果种子设定进程可以取消线程,则不需要取消令牌,对吗?:)因此,
    CancellationToken
    用于发送信号。你需要处理信号还有一件事。。。这也是一个很好的设计,因为在取消之前,您的代码可能需要处理一些对象或句柄。仅仅从外部“杀死”线程就可能产生内存/资源问题。最好让线程处理取消。