У меня длительная операция, которую я хочу отменить, скажем, через 5 секунд. К сожалению, опрос для IsCancellationRequested невозможен (длинная история).
Я использовал код ниже, чтобы бросить исключение OperationCanceledException в обратный вызов отмены. Я хотел перехватить исключение в главном потоке и обработать его, чтобы полностью выйти из приложения.
Похоже, что это не работает должным образом, так как это приводит к необработанному исключению, и приложение не завершается корректно.
Любая помощь приветствуется. Спасибо!
void TestTimeOut()
{
var cts = new CancellationTokenSource();
cts.CancelAfter(5000);
try
{
var task = Task.Run(() => LongRunningOperation(cts.Token));
task.ContinueWith(t => Console.WriteLine("Operation cancelled"), TaskContinuationOptions.OnlyOnFaulted);
task.Wait();
}
catch (AggregateException e)
{
//Handle
}
}
void LongRunningOperation(CancellationToken token)
{
CancellationTokenRegistration registration = token.Register(
() =>
{
throw new OperationCanceledException(token);
});
using (registration)
{
// long running operation here
}
}
В вашем коде много No-No-es, но я думаю, вы просто используете его в качестве демонстрации для своей проблемы. TaskCompletionSource
является TaskCompletionSource
, моя демка тоже ужасна, слишком много слоев Task.Run(), если вы используете Async, вы должны выполнить асинхронизацию до конца. Так что не используйте его в PRD, изучите TaskCompletionSource
самостоятельно и TaskCompletionSource
лучшее решение.
static void LongRunningOperation(CancellationToken token)
{
TaskCompletionSource<int> tcs1 = new TaskCompletionSource<int>();
token.Register(() => { tcs1.TrySetCanceled(token); });
Task.Run(() =>
{
// long running operation here
Thread.Sleep(10000);
tcs1.TrySetResult(0);
}, token);
tcs1.Task.Wait();
}
Вы перехватываете AggregateException
но фактически создаете исключение OperationCanceledException
которое не будет перехвачено.
Изменить, чтобы поймать все типы исключений, таких как
catch (Exception ex) { ... }
Разрешить.
.Wait()
это? ИспользованиеCancellationToken
является кооперативным. Может быть, вы можете просто создать поток, если вы на самом деле не используете асинхронные функции (ключевое слово await).