C# 使用CancellationTokenSource取消多线程

本文详细介绍了如何使用C#中的CancellationTokenSource来优雅地取消正在运行的多线程任务,包括单个线程和多个线程的同时取消。通过实际代码示例,解释了cts.Cancel()与cts.Token.ThrowIfCancellationRequested()的作用机制。

有时间我们在使用多线程的时候,需要取消线程的执行,可以使用CancellationTokenSource来取消对Task开辟多线程的取消

如下:我们点击一个按钮开启线程,然后点击取消按钮取消该线程的执行

 CancellationTokenSource cts ;
        /// <summary>
        /// 开启线程
        /// </summary>
        private void button1_Click(object sender, EventArgs e)
        {
            //重新实例化cts.Token就会不一样,不然再次点击的时候会报错,提示线程已经执行完毕
            cts = new CancellationTokenSource();

            Task task = new Task(() =>
            {
                Thread.Sleep(1500);

                try
                {
                    cts.Token.ThrowIfCancellationRequested();
                    MessageBox.Show("线程被执行");
                }
                catch (Exception ex)
                {
                    MessageBox.Show("线程被取消");
                }

            }, cts.Token);
            task.Start();

            //如果放到这里有可能线程还没有开始执行就被取消了
            //cts.Cancel(true);
        }

        /// <summary>
        /// 取消线程
        /// </summary>
        private void button2_Click(object sender, EventArgs e)
        {
            cts.Cancel();
        }

  

  几点关键问题解释:

 1:为什么线程里边去调用 Thread.Sleep(1500);

          因为如果不让线程暂停一下,你在点击开启线程后。还没有来得及点击取消线程,线程都已经执行完毕了这个时候

          再去取消线程是没有什么意义的。

2: cts.Cancel()

          这句话其实只是设置一个状态,设置该对象一个熟悉为true而已,也就是设置cts.IsCancellationRequested为ture。

          所以他根本没有真正的去取消线程的执行,只是设置一个状态而已。

3:cts.Token.ThrowIfCancellationRequested();

          因为上面说的cts.Cancel()只是设置一个状态而已,线程不会真正被取消。其实线程开启后,现在都是要执行完的,

         我们并不能真正去取消线程的执行,只是从逻辑上去取消线程需要处理的逻辑。

         这句话的意思其实就是检查cts.Cancel()设置的属性状态,也就是cts.IsCancellationRequested是否为true,如果为

         true就抛出一个异常,从而终止线程的执行

         也就是说其实这句话完全可以我们自己来实现

          

同时取消多个线程:

同时取消多个线程,其实也很简单,我们不需要有多少个线程就去实例化多少个CancellationTokenSource,

多个线程绑定顶一个CancellationTokenSource的token然后调用该对象的cancel就可以同时取消多个线程了。

 CancellationTokenSource cts;
        /// <summary>
        /// 开启线程
        /// </summary>
        private void button1_Click(object sender, EventArgs e)
        {
            //重新实例化cts.Token就会不一样,不然再次点击的时候会报错,提示线程已经执行完毕
            cts = new CancellationTokenSource();

            for (int i = 0; i < 5; i++)
            {
                Task task = new Task((obj) =>
                {
                    Thread.Sleep(1500);

                    try
                    {
                        //cts.Token.ThrowIfCancellationRequested();
                        //检查状态,检查线程是否已经被取消,如果取消则自己跑出来一个线程
                        if (cts.Token.IsCancellationRequested)
                            throw new OperationCanceledException();
                        MessageBox.Show("线程" + obj + "被执行");
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("线程" + obj + "被取消");
                    }

                }, i, cts.Token);
                task.Start();
            }
            //如果放到这里有可能线程还没有开始执行就被取消了
            //cts.Cancel(true);
        }

        /// <summary>
        /// 取消线程
        /// </summary>
        private void button2_Click(object sender, EventArgs e)
        {
            cts.Cancel();
        }

原文地址

C# 使用CancellationTokenSource取消多线程 - 剑轩的专栏 - TNBLOG

<think>我们被要求使用中文回答,并且遵循特定的格式要求。 用户的问题是关于C#使用CancellationTokenSource取消线程任务的示例。 根据提供的引用,我们可以总结出以下关键点: 1. CancellationTokenSource用于创建取消令牌(CancellationToken),并通知取消操作。 2. 我们可以通过调用CancellationTokenSource的Cancel方法来请求取消操作。 3. 在任务中,我们需要检查CancellationToken的状态(通过IsCancellationRequested属性)或调用ThrowIfCancellationRequested方法(该方法会在取消时抛出OperationCanceledException)。 我们将提供一个示例,展示如何使用CancellationTokenSource取消一个线程任务(这里我们使用Task来演示,因为Task是更现代的方式,而且引用中也使用了Task)。 注意:用户要求的是“取消线程任务”,但实际在C#中,我们通常使用Task来表示异步操作,而Thread类也可以使用类似机制(通过轮询等)。不过,引用中主要使用了Task,所以我们以Task为例。 示例步骤: 1. 创建CancellationTokenSource实例。 2. 获取CancellationToken。 3. 启动一个任务,在任务中定期检查取消请求。 4. 在需要取消的时候,调用CancellationTokenSource的Cancel方法。 我们将创建一个简单的Windows Forms应用程序(或控制台应用)来演示,但为了简单,我们写一个控制台应用的示例。 同时,根据引用[3]中的代码,我们需要注意: - 在任务中,我们可以通过检查cts.Token.IsCancellationRequested来判断是否取消,或者使用cts.Token.ThrowIfCancellationRequested()来抛出异常。 - 如果使用ThrowIfCancellationRequested,我们需要在任务中捕获异常,或者让调用者知道任务被取消了。 我们将编写一个控制台应用程序示例,模拟一个长时间运行的任务,并允许用户按一个键来取消任务。 但是,由于用户要求的是“线程任务”,我们也可以使用Thread类,但更推荐使用Task,因为Task内置了对CancellationToken的支持。 下面我们提供两个示例:一个使用Task,另一个使用Thread(为了全面)。 然而,引用[4]提到,在异步任务中取消,所以Task是更常见的。但为了满足用户可能的需求,我们提供Task的示例。 根据引用[3],我们也可以看到使用Task的示例。 我们决定以Task为主,因为这是现代C#编程中推荐的方式。 示例代码(控制台应用):</think>### C# 使用 CancellationTokenSource 取消线程任务示例 在 C# 中,`CancellationTokenSource` 是取消异步操作或线程任务的标准机制,它通过协作式取消模式实现安全的任务终止。以下是完整示例: ```csharp using System; using System.Threading; using System.Threading.Tasks; class Program { static CancellationTokenSource cts = new CancellationTokenSource(); static void Main() { // 启动任务 Task.Run(() => DoWork(cts.Token), cts.Token); Console.WriteLine("按任意键取消任务..."); Console.ReadKey(); // 请求取消 cts.Cancel(); Console.WriteLine("已发送取消请求"); Console.ReadKey(); } static void DoWork(CancellationToken token) { try { Console.WriteLine("任务开始"); for (int i = 0; i < 10; i++) { // 检查取消请求 token.ThrowIfCancellationRequested(); Console.WriteLine($"处理中: {i}/10"); Thread.Sleep(1000); // 模拟工作 } Console.WriteLine("任务完成"); } catch (OperationCanceledException) { Console.WriteLine("任务被取消"); // 清理资源 } } } ``` #### 关键机制说明: 1. **取消令牌传递** 通过 `cts.Token` 将取消令牌传递给任务,建立取消通道[^2] 2. **取消检查方式** - `ThrowIfCancellationRequested()`:直接抛出 `OperationCanceledException` - `IsCancellationRequested`:手动检查取消状态(适合需执行清理的场景) 3. **取消请求处理** 调用 `cts.Cancel()` 会: - 将令牌状态标记为取消 - 触发所有注册的回调方法 - 传播取消请求到所有关联令牌[^4] 4. **资源清理** 在 `catch` 块或通过 `token.Register()` 执行必要清理: ```csharp token.Register(() => { Console.WriteLine("释放资源"); }); ``` #### 多任务取消示例: ```csharp // 创建关联令牌源 var linkedCts = CancellationTokenSource.CreateLinkedTokenSource( cts1.Token, cts2.Token ); // 启动多个任务 var tasks = new Task[3]; for (int i = 0; i < tasks.Length; i++) { tasks[i] = Task.Run(() => { linkedCts.Token.ThrowIfCancellationRequested(); // ...工作代码... }, linkedCts.Token); } // 取消所有任务 linkedCts.Cancel(); ``` > **最佳实践**: > 1. 始终传递 `CancellationToken` 到异步方法 > 2. 在循环和长时间操作前检查取消状态 > 3. 使用 `CreateLinkedTokenSource` 组合多个取消源 > 4. 避免在 `finally` 块中使用阻塞操作[^4]
评论 11
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值