如何取消任务但等到它完成?
How to cancel Task but wait until it finishes?
我有线程任务,它在循环中执行一些操作:
static void TaskAction(CancellationToken ct)
{
while (SomeCondition())
{
DoSomeSeriousJob();
ct.ThrowIfCancellationRequested();
}
}
static void DoSomeSeriousJob()
{
Console.WriteLine("Serious job started");
Thread.Sleep(5000);
Console.WriteLine("Serious job done");
}
我启动它然后在一段时间后取消:
var cts = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => TaskAction(cts.Token), cts.Token);
Thread.Sleep(1000);
cts.Cancel();
这个操作必须正确完成,我不想打断它。但我想向我的任务发送取消请求 并等待它正确完成 (我的意思是它到达代码中的某个点)。
我尝试了以下方法:
1。等待(CancellationToken ct)
try
{
task.Wait(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
// Must be joined here.
在这种情况下,立即从 Wait()
编写 returns。任务继续 运行 直到 ThrowIfCancellationRequested()
,但如果主线程退出,任务也会被中断。
2。等待()
try
{
task.Wait();
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
此处主线程等待完成,但最后 AggregateException
上升为 InnerException
= TaskCancelledException
(不是 OperationCancelledException
)。
3。检查 IsCancellationRequested() 没有异常
static void TaskAction(CancellationToken ct)
{
while (SomeCondition())
{
DoSomeSeriousJob();
if (ct.IsCancellationRequested)
break;
}
}
// ...
task.Wait();
在这种情况下,没有出现异常,但任务最终获得状态 RanToCompletion
。当 SomeCodition()
开始为 return false.
时,这与正确完成无法区分
所有这些问题都有简单的解决方法,但我想知道,我可能遗漏了什么?谁能告诉我更好的解决方案?
如果你想等待任务同步完成(或被取消),你可以试试这个:
cts.Cancel();
Task.Run(async () => {
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
).Wait();
这样您就可以直接捕获 OperationCanceledException 而不是捕获 AggregateException。
编辑:
等待(CanecllationToken)
此方法不适用于该目的。
MSDN 声明:
Waits for the Task to complete execution. The wait terminates if a cancellation token is canceled before the task completes.
等待()
您可以使用此方法,但如您所见,您应该期待 AggregateException 而不是 OperationCanceledException。在方法的documents中也有指定。
The AggregateException.InnerExceptions collection contains a TaskCanceledException object.
所以在这种方法中,为了确保操作被取消,您可以检查内部预期是否包含 TaskCanceledException。
检查 IsCancellationRequested() 无异常
这样一来,很明显没有抛出异常,也不知道操作是否取消了。
如果您不想同步等待,一切都按预期进行:
cts.Cancel();
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
试试这个:
try
{
task.GetAwaiter().GetResult();
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
你会得到一个 OperationCanceledException
,它不会被 AggregateException
包裹。
我有线程任务,它在循环中执行一些操作:
static void TaskAction(CancellationToken ct)
{
while (SomeCondition())
{
DoSomeSeriousJob();
ct.ThrowIfCancellationRequested();
}
}
static void DoSomeSeriousJob()
{
Console.WriteLine("Serious job started");
Thread.Sleep(5000);
Console.WriteLine("Serious job done");
}
我启动它然后在一段时间后取消:
var cts = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => TaskAction(cts.Token), cts.Token);
Thread.Sleep(1000);
cts.Cancel();
这个操作必须正确完成,我不想打断它。但我想向我的任务发送取消请求 并等待它正确完成 (我的意思是它到达代码中的某个点)。 我尝试了以下方法:
1。等待(CancellationToken ct)
try
{
task.Wait(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
// Must be joined here.
在这种情况下,立即从 Wait()
编写 returns。任务继续 运行 直到 ThrowIfCancellationRequested()
,但如果主线程退出,任务也会被中断。
2。等待()
try
{
task.Wait();
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
此处主线程等待完成,但最后 AggregateException
上升为 InnerException
= TaskCancelledException
(不是 OperationCancelledException
)。
3。检查 IsCancellationRequested() 没有异常
static void TaskAction(CancellationToken ct)
{
while (SomeCondition())
{
DoSomeSeriousJob();
if (ct.IsCancellationRequested)
break;
}
}
// ...
task.Wait();
在这种情况下,没有出现异常,但任务最终获得状态 RanToCompletion
。当 SomeCodition()
开始为 return false.
所有这些问题都有简单的解决方法,但我想知道,我可能遗漏了什么?谁能告诉我更好的解决方案?
如果你想等待任务同步完成(或被取消),你可以试试这个:
cts.Cancel();
Task.Run(async () => {
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
).Wait();
这样您就可以直接捕获 OperationCanceledException 而不是捕获 AggregateException。
编辑:
等待(CanecllationToken)
此方法不适用于该目的。 MSDN 声明:
Waits for the Task to complete execution. The wait terminates if a cancellation token is canceled before the task completes.
等待()
您可以使用此方法,但如您所见,您应该期待 AggregateException 而不是 OperationCanceledException。在方法的documents中也有指定。
The AggregateException.InnerExceptions collection contains a TaskCanceledException object.
所以在这种方法中,为了确保操作被取消,您可以检查内部预期是否包含 TaskCanceledException。
检查 IsCancellationRequested() 无异常
这样一来,很明显没有抛出异常,也不知道操作是否取消了。
如果您不想同步等待,一切都按预期进行:
cts.Cancel();
try {
await task;
}
catch (OperationCanceledException ex) {
// ...
}
试试这个:
try
{
task.GetAwaiter().GetResult();
}
catch (OperationCanceledException)
{
Console.WriteLine("Task cancelled");
}
你会得到一个 OperationCanceledException
,它不会被 AggregateException
包裹。