Task cancellation in C# and things you should know about it

本文介绍了C#中任务取消机制的基础知识,包括如何创建和使用取消令牌,如何观察取消令牌的状态,以及如何发送取消请求。文章还探讨了不同的取消方法,并提供了一些实际应用的例子。

refs:

https://binary-studio.com/2015/10/23/task-cancellation-in-c-and-things-you-should-know-about-it/



Task mechanism in C# is a powerful beast in the area of parallel and asynchrony programming. Controlling this beast may take lots of efforts and pain. .NET Framework 4 introduces a convenient approach for cancellation of asynchronous operations.

How do we control

Why should we control execution flow of the tasks? One reason is business logic or algorithm requirements. Another reason comes from an idea, that there should be no unobserved tasks. Such tasks may hold thread pool and CPU resources and therefore be dangerous.

Just for this .NET provides us with two classes:

  • CancellationTokenSource – object responsible for creating cancellation token and sending cancellation request to all copies of that token.
  • CancellationToken – structure used by listeners to monitor token current state.

How do we pass token

Firstly, we should somehow make task use created token. One way is to pass it as an argument to the method responsible for creating task.

With such approach token is only checked at the very beginning, before starting execution of task delegate code. If token cancelled then task is also put in canceled mode. In the example above message won’t be printed because token had been canceled before task were created.

But what if we want to stop task execution in particular moment of time? Then you should observe cancellation token state manually inside task delegate. There are generally two ways for passing token inside task delegate.

First way is to make token variable visible by task delegate. It can be accomplished by using global variable or variable capture.

Second way is to pass token as state object and downcast it inside task delegate.

How do we observe token

Now that we know how to access token inside a task, it is time to become acquainted with how we can observe token state. You can observe it in the three ways: by polling, using callback registration and via wait handle.

1. By polling – periodically check IsCancellationRequested property

2. Callback registration – provide callback that would be executed right after cancellation is requested

3. Waiting for wait handle provided by CancellationToken.

You can also observe multiple tokens simultaneously, by creating linked token source that can join multiple tokens into one.

How do we cancel

We already know how to pass and observe tokens. What is left is how we send cancellation request. For cancelling, we use CancellationTokenSource object. Cancellation request may be direct or deferred.

When we use Cancel method directly, it implicitly calls all registered callbacks on current thread. If callbacks throw exceptions, they are wrapped in AggregateException object that propagated then to caller.

Since callbacks is called one by one, optional boolean argument for Cancel method lets you specify behavior upon encountering exception in any of the registered callbacks.

If argument is true then exception will immediately propagate out of the call to Cancel, preventing the remaining callbacks from executing.

If argument is false, all registered callbacks will be executed with all thrown exceptions wrapped into the AggregateException.

After detecting cancellation request inside task, common approach is to throw OperationCanceledException object, to put task in canceled state.

Conclusion

Task cancellation mechanism is an easy and useful tool for controlling task execution flow. It is a part of big .NET Framework ecosystem, therefore its usage in most cases is more preferable than some custom solutions.

 


### C#Task 的基本使用 #### 判断 Task 是否成功完成 在 C# 中,`Task` 是异步编程的核心组件之一。为了判断一个 `Task` 是否已经成功执行完毕,可以检查其状态属性 `Status`。如果该属性等于 `TaskStatus.RanToCompletion`,则表示此任务已正常结束而未发生任何错误或被取消。 ```csharp if (task.Status == TaskStatus.RanToCompletion) { Console.WriteLine("The task has successfully completed."); } ``` 上述代码片段展示了如何通过比较 `Task` 对象的状态来验证它是否顺利完成[^1]。 #### 创建并启动一个新的 Task 除了直接实例化 `Task` 并调用它的 `Start()` 方法外,还可以利用工厂模式下的静态方法更简便地创建与初始化新的线程任务。具体而言,可以通过 `Task.Factory.StartNew(Action action)` 来实现这一目的。 下面是一个简单的例子: ```csharp var myTask = Task.Factory.StartNew(() => { for(int i=0;i<5;i++) { Console.WriteLine($"Executing iteration {i}"); Thread.Sleep(100); } }); myTask.Wait(); Console.WriteLine("My Task is done!"); ``` 这里定义了一个匿名函数作为参数传递给 `StartNew` 方法,这个函数将在单独的任务中运行五次打印语句,并且每次之间暂停一百毫秒模拟工作负载。最后等待直到我的自定义任务完成后才继续主线程流程[^2]。 #### 取消正在运行中的 Task 当需要提前终止某些长时间运行的操作时,可以借助于 .NET 提供的 cancellation mechanism(取消机制)。这通常涉及到两个主要角色——`CancellationTokenSource` 和关联的 `CancellationToken` 实例。前者负责发出取消信号;后者嵌入目标逻辑内部以便监听外部变化情况进而采取适当行动比如中断当前进程或者释放资源等处理措施。 以下是从参考资料改编的一个实际应用案例说明了怎样安全有效地停止正在进行的工作单元: ```csharp static void DoWork(CancellationToken token) { try{ for (int i = 0; i < 10 && !token.IsCancellationRequested; i++) { // Check periodically whether a cancel request was made. token.ThrowIfCancellationRequested(); Console.WriteLine($"DoWork: Working on item #{i + 1}"); // Simulate work by sleeping the thread briefly. System.Threading.Thread.Sleep(500); } if (!token.IsCancellationRequested){ Console.WriteLine("All items processed."); } }catch(OperationCanceledException ex){ Console.WriteLine("Operation canceled before completion.",ex.Message); } } // Usage Example: public static async Task Main(string[] args){ var cts=new CancellationTokenSource(); _=Task.Run(()=>DoWork(cts.Token)); await Task.Delay(TimeSpan.FromSeconds(3)); // Let it run few iterations cts.Cancel(); // Request to stop further processing after some time. } ``` 在这个扩展版本里增加了异常捕获块用来妥善管理因主动触发退出而导致可能出现的预期之外状况的同时也保留原始功能不变即一旦接收到撤回指令立即响应不再做额外无谓尝试直至完全清理现场为止[^3].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值