2016-07-17 120 views
0

另一种方式我有取消任务

class Program 
{ 
    private static void MyTask(object obj) 
    { 
     var cancellationToken = (CancellationToken) obj; 
     if(cancellationToken.IsCancellationRequested) 
      cancellationToken.ThrowIfCancellationRequested(); 

     Console.WriteLine("MyTask() started"); 
     for (var i = 0; i < 10; i++) 
     { 
      try 
      { 
       if (cancellationToken.IsCancellationRequested) 
        cancellationToken.ThrowIfCancellationRequested(); 

      } 
      catch (Exception ex) 
      { 
       return; 
      } 


      Console.WriteLine($"Counter in MyTask() = {i}"); 
      Thread.Sleep(500); 
     } 
     Console.WriteLine("MyTask() finished"); 
    } 
    static void Main(string[] args) 
    { 
     var cancelationTokenSource = new CancellationTokenSource(); 
     var task = Task.Factory.StartNew(MyTask, cancelationTokenSource.Token, 
      cancelationTokenSource.Token); 

     Thread.Sleep(3000); 

     try 
     { 
      cancelationTokenSource.Cancel(); 
      task.Wait(); 
     } 
     catch (Exception ex) 
     { 
      if(task.IsCanceled) 
       Console.WriteLine("Task has been cancelled"); 

      Console.WriteLine(ex.Message); 
     } 
     finally 
     { 
      cancelationTokenSource.Dispose(); 
      task.Dispose(); 
     } 

     Console.WriteLine("Main finished"); 
     Console.ReadLine(); 
    } 
} 

我想开始新的任务,并在一段时间后取消一个简单的控制台应用程序。是否有任何其他方式来实现这个结果而不是使用这个

if(cancellationToken.IsCancellationRequested) 
     cancellationToken.ThrowIfCancellationRequested(); 

for循环中的每次迭代?为什么我们必须在每次迭代时检查cancellationToken.IsCancellationRequested,也许我们可以使用其他的东西?

+3

就是这么做的。当你有一个很长的任务p时,就是这样实现的,以便允许中断。 –

+0

@DanielProtopopov如果任务被取消,我们必须单次检查evey –

+0

即使在汇编程序中它是如何完成的 - 一个在循环之外控制的变量 - 你期望什么? –

回答

1

在这种特定情况下,您可以避免使用.ThrowIfCancellationRequested(),而只需使用break来停止执行循环,然后完成Task。在更深的任务树中,ThrowIfCancellationRequested更有用,其中有更多的后代,并且保持取消更加困难。

if (cancellationToken.IsCancellationRequested) 
{ 
    break; 
} 

Stephen Toub有一个good explanation关于OCE投掷是如何更多的承认。

如果任务的身体也监测取消标记,并抛出包含令牌(这是什么ThrowIfCancellationRequested做)的OperationCanceledException,那么当任务看到OCE,它会检查OCE的令牌是否匹配该任务的令牌。如果是,则将该异常视为确认协作取消,并且任务转换为取消状态(而不是故障状态)。

0

不知道你的反对在每个迭代上检查是什么,但如果你不想去检查每一次迭代,不管出于什么原因,检查i值:

例如此检查每10个循环:

if (i % 10 == 0 && cancellationToken.IsCancellationRequested) 

你必须检查的原因是,这样你就可以决定哪里是最好停止工作,这样的工作是不是不一致的状态。虽然所有你通过不频繁检查来实现的任务是一个取消较慢的任务,也许这会导致一个不太敏感的用户体验。例如。任务将在500ms之前结束,现在可能需要10x,5秒。

但是,如果每个循环非常快,并且每个循环检查标志都会证明显着增加了任务花费的总时间,然后检查每个循环是否有效。