2016-10-28 241 views
0

我在處理任務和取消令牌時遇到了一些問題。我做了一個程序,它看起來像這樣:(?雖然我不包括Thread.Sleep()for循環似乎運行之前,任務甚至開始)c#異步任務取消

static void Main(string[] args) 
{ 

    CancellationTokenSource token = new CancellationTokenSource(); 
    Stopwatch stop = new Stopwatch(); 
    stop.Start(); 

    for (int i = 0; i < 5; i++) 
    { 
     //Thread.Sleep(1000); 
     Task.Factory.StartNew(() => myLongTask(token.Token, (i + 1) * 1000)); 
    } 
    while (true) 
    { 
     Thread.SpinWait(1000); 
     if (stop.ElapsedMilliseconds > 3000) 
     { 
      token.Cancel(); 
     } 
    } 
} 

public static void myLongTask(CancellationToken token, int time) 
{ 
    if (token.IsCancellationRequested) 
    { 
     Console.WriteLine("Cancelled"); 
     return; 
    } 
    var sw = Stopwatch.StartNew(); 
    Console.WriteLine($"Task {time/1000} started"); 
    while (sw.ElapsedMilliseconds < time) 
     Thread.SpinWait(1000); 
    Console.WriteLine($"Task {time/1000} ended"); 

} 

我同時運行5個任務。當我運行程序時,任何任務都不會取消。另外什麼是竊聽我是...什麼任務我真的取消時調用token.Cancel()?我怎樣才能選擇我要殺的5個任務中的哪一個?我可以通過它的變量來定義每個任務,但我不能訪問它的屬性,因爲它是由CancellationToken觸發的。我需要5個不同的標記嗎?

回答

8

當我運行該程序時,任何任務都不會取消。

這是因爲您只在任務的開始處檢查取消標記。一旦它通過了第一個token.IsCancellationRequested檢查,取消令牌就什麼也不做。如果你移動你的支票存入你的循環,像這樣:

while (sw.ElapsedMilliseconds < time) 
{ 
    if (token.IsCancellationRequested) 
    { 
     Console.WriteLine("Cancelled"); 
     return; 
    } 
    Thread.SpinWait(1000); 
} 

...然後你會看到任務作出適當的反應。

另外什麼是竊聽我是...什麼任務,我真的取消時調用token.Cancel()

您不取消任務 - 取消取消令牌。 觀察到的任何任務取消標記將被取消(或完成,或執行任何操作),但任務與標記之間沒有直接關聯。

當我們談論「取消任務」時,我們的意思是「取消我們相信任務正在觀察的令牌」。

+0

但是,如果我有5個不同的任務,只有一個'token.Cancel()'...那麼它顯然取消所有5個?如果我想殺死一個特定的任務,我是否需要一個令牌列表? – Norgul

+0

@Norgul:是的,你會的。或者至少,你需要5個不同的標記和*某種方式來知道你想要停止的任務正在觀察哪一個。 –