CancellationTokenSource.Cancel создает исключение
Поскольку я читаю документацию, CancellationTokenSource.Cancel не должен выдавать исключение.
CancellationTokenSource.Cancel
Под вызовом cts.Cancel(); вызывает (не выбрасывает) исключение OperationCanceledException.
Я очень уверен в этом, как будто я комментирую эту строку, тогда последнее OperationCanceledException не выбрасывается.
При активной строке cts.Cancel строка, которая выдает исключение, является t2.Wait(token);
И если у меня есть задержка в cts.Cancel(); затем t2.Wait (токен); не выдает исключение, как только вызывается строка.
t2.Wait (маркер); генерирует это исключение только при запуске cts.Cancel ().
Это правильное поведение?
Если это соответствует, то я могу жить с этим, но я не хочу, чтобы cts.Cancel вызывал исключение.
Я явно сбит с толку - я просто хочу понять поведение, чтобы чувствовать себя комфортно, перенося это в производственную среду.
Прямо сейчас я делаю это с BackGroundWorker, и я подумал, что смогу упростить отслеживание и поддержку, используя ожидание и отмену.
if (token.IsCancellationRequested || ctr == 100000000)
все еще бросает на ctr == 100000000
Я все еще вижу, что внутреннее OperationCanceledException перехватывается, а внешний (нижний) вообще не генерируется.
Что-то не так с этим кодом?
Или это так должно работать?
Без перехвата попытки в Task t2 = Task.Run я получил неперехваченное исключение.
Я думал, что это было бы поймано попыткой поймать t2.Wait, но один вопрос за один раз.
Это консольное приложение в.NET 4.5.
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task.Run(() =>
{
Thread.Sleep(1000);
cts.Cancel(); // this is thowing an exception that is caught on the last catch (OperationCanceledException Ex)
// according to the documentation this is not supposed
// if I comment out the cts.Cancel(); then the exeption is not thrown
if (token.IsCancellationRequested)
Console.WriteLine("Cancellation requested in Task {0}.",
Task.CurrentId);
else
Console.WriteLine("Cancellation Not requested in Task {0}.",
Task.CurrentId);
}, token);
//tried this but did not help
//Task.Run(() =>
//{
// //Thread.Sleep(1000);
// if (token.IsCancellationRequested)
// Console.WriteLine("Cancellation requested in Task {0}.",
// Task.CurrentId);
//}, token);
//Thread.Sleep(1000);
////cts.Cancel();
Task t2 = Task.Run(() =>
{
try
{
Console.WriteLine("Task t2 started Int32.MaxValue = " + Int32.MaxValue.ToString());
Thread.Sleep(4000);
for (int ctr = 0; ctr < Int32.MaxValue; ctr++)
{
if (ctr < 100 || ctr % 100000000 == 0)
{
Console.WriteLine(ctr.ToString());
}
if (token.IsCancellationRequested || ctr == 100000000) // || ctr == 100000000
{
Console.WriteLine("ThrowIfCancellationRequested in t2 Task {0}.",
Task.CurrentId);
throw new OperationCanceledException(token);
//token.ThrowIfCancellationRequested();
}
}
Console.WriteLine("Task {0} finished.",
Task.CurrentId);
}
catch (OperationCanceledException Ex)
{
//Console.WriteLine(Ex.ToString());
Console.WriteLine("OperationCanceledException in Task t2 {0}: The operation was cancelled.",
Task.CurrentId);
}
catch (Exception Ex)
{
Console.WriteLine("Task t2 = Task.Run Exception Ex" + Ex.Message);
}
});
try
{
Console.WriteLine("t2.Wait a");
t2.Wait(token);
}
catch (AggregateException e)
{
Console.WriteLine("AggregateException");
foreach (var v in e.InnerExceptions)
Console.WriteLine(e.Message + " " + v.Message);
}
catch (OperationCanceledException Ex)
{
//Console.WriteLine(Ex.ToString());
Console.WriteLine("OperationCanceledException in Task {0}: The operation was cancelled.",
t2.Id);
}
catch (Exception Ex)
{
Console.WriteLine(Ex.ToString());
}
Console.WriteLine("end");
Console.ReadLine();
}
3 ответа
t2.Wait(token);
должен бросить примерно через 1 сек, потому что token
отменено
Линия
cts.Cancel();
не может быть брошен, если "Cancellation requested in Task {0}."
был напечатан на консоли, как вы сказали, что это было.
Да, это ожидаемое поведение: перегрузка Task.Wait
токен отмены ожидает, пока:
- Задача, которую вы ждете, завершена
- Переданный в аннулировании токен аннулируется.
В последнем случае, когда Task.Wait
отмечает, что переданный в токене был отменен, он генерирует исключение OperationCancelledException. Вот стек вызовов, когда исключение срабатывает в вашем случае
mscorlib.dll!System.Threading.CancellationToken.ThrowOperationCanceledException() Line 505 + 0x4d bytes C#
mscorlib.dll!System.Threading.ManualResetEventSlim.Wait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) Line 642 C#
mscorlib.dll!System.Threading.Tasks.Task.SpinThenBlockingWait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) Line 3284 + 0xf bytes C#
mscorlib.dll!System.Threading.Tasks.Task.InternalWait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) Line 3223 + 0x10 bytes C#
mscorlib.dll!System.Threading.Tasks.Task.Wait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) Line 3129 + 0xc bytes C#
mscorlib.dll!System.Threading.Tasks.Task.Wait(System.Threading.CancellationToken cancellationToken) Line 3064 + 0xe bytes C#
> ConsoleApplication1.exe!ConsoleApplication1.Program.Main(string[] args) Line 82 + 0x15 bytes C#
Что касается вашей второй части вопроса: если вы - удалили try / catch в течение t2 и - вы никогда не отменили токен,
тогда вы окажетесь в своем внешнем AggregateException
обработчик (так как вызов t2.Wait
бросил бы AggregateException
с одним внутренним исключением, которое будет OperationCanceledException
что ты бросил.
Я могу ошибаться по этому поводу, но причина, по которой вы получаете это исключение, заключается в том, что вы отменяете ту же задачу, в которую вы поместили оператор отмены. В документации MSDN операции CanceledException говорится следующее:
The exception that is thrown in a thread upon cancellation of an operation that the thread was executing.
Можете ли вы попробовать изменить первое задание, вызовите следующее и убедитесь, что вы все еще получаете исключение: -
Task.Run(() =>
{
Thread.Sleep(1000);
if (token.IsCancellationRequested)
Console.WriteLine("Cancellation requested in Task {0}.",
Task.CurrentId);
}, token);
cts.Cancel();
Полезная ссылка для taskCancellationSource: -
http://johnbadams.wordpress.com/2012/03/10/understanding-cancellationtokensource-with-tasks/