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 Всякий раз, когда задача еще не перешла на 'Running'. Например, если вы вызываете 'ContinueWith' в задаче и эта задача отменяется, продолжение будет отменено также –

+0

Еще раз спасибо. Я просто нашел http://stackoverflow.com/a/10444108/492336, где они объясняют, что передача «токена» в «StartNew» специально предназначена для включения этого поведения и, действительно, не передает токен в «StartNew()», тот же эффект, что и uncommenting '// Sleep (1)'. – sashoalm