2013-03-15 57 views
17

我可以获得CancellationToken,它在执行任务操作期间传递给Task构造函数。大多数样品的这个样子:获取任务CancellationToken

CancellationTokenSource cts = new CancellationTokenSource(); 
CancellationToken token = cts.Token; 

Task myTask = Task.Factory.StartNew(() => 
{ 
    for (...) 
    { 
     token.ThrowIfCancellationRequested(); 

     // Body of for loop. 
    } 
}, token); 

但是,如果我的行为是不是拉姆达但放在其他类中的方法,我没有token直接访问?唯一的办法是通过token作为状态?

回答

8

但是,如果我的操作不是lambda,而是放置在其他类中并且我没有直接访问令牌?唯一的办法是将令牌作为状态传递给它?

是的,在这种情况下,您需要传递装箱状态的令牌或包含在您用作状态的其他类型中。

但是,只有在计划在方法内使用CancellationToken时才需要。例如,如果您需要拨打token.ThrowIfCancellationRequested()

如果您只使用令牌来防止该方法被安排,那么它不是必需的。

+4

你也需要的,如果你想通过它传递给子任务的任务,这是需要做一个平常的事内开始。我希望'Task'暴露了给定的CancellationToken。 – Servy 2013-03-15 18:07:17

10

我可以在任务执行期间获取传递给任务构造函数的CancellationToken吗?

不,你不能直接从Task对象,没有。

但是,如果我的操作不是lambda,而是放置在其他类中并且我没有直接访问令牌?唯一的办法是将令牌作为状态传递给它?

这些是两个选项,是的。还有其他人。 (可能不是一个包容性的列表)。

  1. 您可以关闭在取消标记在一个匿名方法

  2. 你可以把它作为国家

  3. 可以确保使用的实例因为任务的委托拥有一个实例字段,保存到取消标记上,或者保存到保存在令牌上的某个对象上等。

  4. 您可以通过其他更大的sco PE作为国家,即作为公共静态字段(不好的做法,在大多数情况下,但它有可能适用)

6

至于其他的答案中的状态,您可以通过令牌作为参数传递给你的方法。但是,请务必记住,您仍然希望将它传递给Task。例如,Task.Factory.StartNew(() => YourMethod(token), token)

这保证:

  1. 如果Task执行之前发生消除(这是一个很好的优化)

  2. OperationCanceledException被调用方法抛出正确转换的任务Task将无法​​运行到Canceled状态

0

你可以得到t他通过反射访问内部字段CancellationToken。

public CancellationToken GetCancellationToken(Task task) 
{ 
    object m_contingentProperties = task 
     .GetType() 
     .GetField("m_contingentProperties", 
      BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) 
     .GetValue(task); 

    object m_cancellationToken = m_contingentProperties 
     .GetType() 
     .GetField("m_cancellationToken", 
      BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) 
     .GetValue(m_contingentProperties); 

    return (CancellationToken)m_cancellationToken; 
} 

提示:你可以用ILSpy自己搜索这些东西。

2

有一个很简单的解决办法:

class CancelingTasks 
{ 
    private static void Foo(CancellationToken token) 
    { 
     while (true) 
     { 
      token.ThrowIfCancellationRequested(); 

      Thread.Sleep(100); 
      Console.Write(".");     
     } 
    } 

    static void Main(string[] args) 
    { 
     CancellationTokenSource source = new CancellationTokenSource(); 
     CancellationToken tok = source.Token; 

     tok.Register(() => 
     { 
      Console.WriteLine("Cancelled."); 
     }); 

     Task t = new Task(() => 
     { 
      Foo(tok); 
     }, tok); 

     t.Start(); 

     Console.ReadKey(); 
     source.Cancel(); 
     source.Dispose(); 

     Console.WriteLine("Main program done, press any key."); 
     Console.ReadKey(); 
    } 
}