1

我以爲CancellationToken/CancellationTokenSource系統有點像C++ volatile bool bFlagCancelled,這意味着任務的取消是自願的,並且依賴任務本身來不時檢查它是否被取消並拋出異常,明確地或通過致電ThrowIfCancellationRequested()不檢查它是否被取消的TPL任務,是否仍被取消?

但是如果我在StartNew()之後立即致電取消,則任務停止,並且調用Wait()將拋出TaskCanceledException

例如,此代碼:

CancellationTokenSource source = new CancellationTokenSource(); 
CancellationToken token = source.Token; 
Task task = Task.Factory.StartNew(
    () => 
    { 
     Console.WriteLine("start sleep"); 
     Thread.Sleep(1000); 
     Console.WriteLine("sleep ended"); 
    } 
    , token); 
// Thread.Sleep(1); 
source.Cancel(); 
Console.WriteLine("start wait"); 
task.Wait(); 
Console.WriteLine("wait ended"); 

我得到這樣的輸出:

start wait 
Exception: System.AggregateException: One or more errors occurred. ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.

但是,如果我去掉// Thread.Sleep(1);,則行爲的變化,我得到這樣的輸出:

start sleep 
start wait 
sleep ended 
wait ended

現在我想也許這是因爲task.Start()尚未被調用,bu t據我瞭解,StartNew()在返回之前調用task.Start() - 這就是爲什麼它沒有同步成本,建議與創建new Task並自己調用task.Start()

那麼這意味着在某些情況下,即使不檢查取消標記,任務也會自動取消。這是發生這種情況的唯一情況嗎,還是有更多的情況發生?

回答

1

Task.Factory.StartNew在返回之前調度任務,但這並不意味着任務實際開始執行。因此,如果TaskScheduler接受它,仍然有空間取消任務(在內部調用TaskScheduler.TryDequeue方法,如果任務返回true,則該任務可以標記爲取消)。

+0

感謝您的回答。有沒有其他的情況發生,或者這是唯一的嗎? – sashoalm

+1

@sashoalm每當任務尚未轉變爲「正在運行」。例如,如果您在任務中調用「ContinueWith」並取消該任務,則繼續也會被取消 –

+0

再次感謝。我剛剛發現http://stackoverflow.com/a/10444108/492336,他們解釋說,將'token'傳遞給'StartNew'是爲了實現這種行爲,並且確實不會將令牌傳遞給'StartNew()'與取消註釋「//睡眠(1)」相同的效果。 – sashoalm