Я думал, что система 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()
самостоятельно.
Итак, это означает, что в некоторых ситуациях задача отменяется самопроизвольно, даже не проверяя токен отмены. Это единственная ситуация, когда это происходит, или есть ли еще сценарии, где это происходит?
Спасибо за ответ. Есть ли другие ситуации, когда это может произойти, или это единственный? – sashoalm
@sashoalm Всякий раз, когда задача еще не перешла на 'Running'. Например, если вы вызываете 'ContinueWith' в задаче и эта задача отменяется, продолжение будет отменено также –
Еще раз спасибо. Я просто нашел http://stackoverflow.com/a/10444108/492336, где они объясняют, что передача «токена» в «StartNew» специально предназначена для включения этого поведения и, действительно, не передает токен в «StartNew()», тот же эффект, что и uncommenting '// Sleep (1)'. – sashoalm