2013-03-15 65 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(); 
    } 
}