多线程之旅(9)_如何安全的取消正在执行的线程——附C#源码
参考网址: https://blog.csdn.net/yangwohenmai1/article/details/90404497
当线程能流畅安全的自动运行后,我们就要考虑一些更风骚的操作,就是如何在线程运行的过程中对线程进行干预。
用Above销毁线程首先过于简单粗暴,强行停止往往会抛出一些未知的错误,而且也丧失了对线程控制的能力。
此时,我们可以通过CancellationTokenSource来优雅的取消一个正在执行的线程。何谓优雅?优雅就是我们在发出指令停止一个线程的时候,线程会判断此时是否可以停止;如果可以停止的话;线程会对当前任务进行一些善后处理;最后,在停止后线程可以返回给我们一些信息告诉我们线程是否已经停掉。
那么,我们怎么去随心所欲的取消这个线程的运行?
Github源码地址:https://github.com/yangwohenmai/TEST/tree/master/TaskCancellationToken
一.通过CancellationTokenSource.Cancel()取消单个任务
1.在用Task.Factory.StartNew启动一个线程时,将CancellationTokenSource.Token参数一起传进去。
2.同时在Task内部设置一个循环去判断CancellationTokenSource.IsCancellationRequested的状态,根据IsCancellationRequested不同的状态编写不同的执行逻辑。
3.当想要取消这个正在执行的线程时,在外部调用CancellationTokenSource对象的Cancel()方法,就会修改IsCancellationRequested的状态。
4.线程内部一旦读取到IsCancellationRequested状态为true,则代表线程取消的信号被触发,线程此时停止继续执行。
代码如下:
#region 取消单个任务
/// <summary>
///
/// </summary>
public static void CancellationTokenTest()
{
//通知 System.Threading.CancellationToken,告知其应被取消。
CancellationTokenSource TokenSource = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => DoWork(TokenSource.Token), TokenSource.Token);
//在这里还可以给token注册了一个方法,输出一条信息 用户输入0后,执行tokenSource.Cancel方法取消任务。这个取消任务执行后,会执行这个代码.
TokenSource.Token.Register(() => { Console.WriteLine("取消");Console.WriteLine("我点击了取消");return; });
//等待用户输入
var input = Console.ReadLine();
if (Convert.ToInt32(input) == 0)
{
//如果输入了0,则取消这个任务;
//一旦cancel被调用。task将会抛出OperationCanceledException来中断此任务的执行,最后将当前task的Status的IsCanceled属性设为true
TokenSource.Cancel();
}
Thread.Sleep(10000);
Console.WriteLine("任务是否完成:" + task.IsCompleted);
Console.WriteLine("任务是否成功:" + task.IsCompletedSuccessfully);
//当线程是因为异常而取消时,IsCanceled字段为true,正常取消时显示为false
Console.WriteLine("任务是否是被手动取消:" + task.IsCanceled);
Console.ReadLine();
}
/// <summary>
/// 使用IsCancellationRequested终止一个线程
/// </summary>
/// <param name="Token"></param>
public static void DoWork(CancellationToken Token)
{
int count = 0;
for (var i = 1; i < 10; i++)
{
Console.WriteLine("i:" + i);
Thread.Sleep(1000);
//判断是否取消任务,取消为true;不取消为false
if (Token.IsCancellationRequested)
{
count++;
Console.WriteLine("取消任务成功!" + count);
if (count == 5)
{
return;
}
}
}
}
#endregion
那这和我们自己在外部设置一个变量,通过修改变量来控制线程线程有什么区别呢?其实本质没区别,就是可读性更好,有现成的为何要自己写,而且也不用担心自己的外部变量被不小心修改。
二.通过CancellationTokenSource.CreateLinkedTokenSource()取消任意一个任务,则所有任务都取消
如果有一堆线程在同时执行,这一堆线程之间是一个事务类型的原子操作,一旦停止的话要一定要同时停止,但我不想把所有线程都单独进行一遍Cancel()操作,那么你就用CancellationTokenSource.CreateLinkedTokenSource这个集合。
这个集合可以将一批线程一起放进集合里,你只要停掉这一批线程中的任意一个,那么这一批线程就会全部停止,听起来是不是很好用?
代码如下:
//声明CancellationTokenSource对象
static CancellationTokenSource c1 = new CancellationTokenSource();
static CancellationTokenSource c2 = new CancellationTokenSource();
static CancellationTokenSource c3 = new CancellationTokenSource();
//使用多个CancellationTokenSource进行复合管理
static CancellationTokenSource compositeCancel = CancellationTokenSource.CreateLinkedTokenSource(c1.Token, c2.Token, c3.Token);
#region 取消任意一个任务,所有的任务都取消
/// <summary>
/// 取消任意一个任务,则所有任务都取消
/// </summary>
public static void CancellationTokenAllTest()
{
var task = Task.Factory.StartNew(() =>
{
for (var i = 1; i < 1000; i++)
{
Console.WriteLine("Hello World!");
Thread.Sleep(1000);
//判断是否取消任务,取消为true;不取消为false
if (compositeCancel.IsCancellationRequested)
{
Console.Write("取消任务成功!");
return;
}
}
}, compositeCancel.Token);
//等待用户输入
var input = Console.ReadLine();
//如果输入了0,则取消c1这个任务,c1取消后,符合管理compositeCancel的状态都取消
if (Convert.ToInt32(input) == 0)
{
//任意一个 CancellationTokenSource 取消任务,那么所有任务都会被取消
c1.Cancel();
}
}
#endregion
3.Register
在CancellationTokenSource.Token之后还有一个Register()方法,这是一个回调方法,当CancellationToken被取消后,就会自动调用Register()内部定义的方法。
这里我们可以进行一些线程停止的善后处理
TokenSource.Token.Register(() =>
{
Console.WriteLine("取消");
Console.WriteLine("我点击了取消");
return;
});
————————————————
版权声明:本文为CSDN博主「日拱一两卒」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yangwohenmai1/article/details/90404497
多线程之旅(9)_如何安全的取消正在执行的线程——附C#源码的更多相关文章
- Java线程状态、线程start方法源码、多线程、Java线程池、如何停止一个线程
下面将依次介绍: 1. 线程状态.Java线程状态和线程池状态 2. start方法源码 3. 什么是线程池? 4. 线程池的工作原理和使用线程池的好处 5. ThreadPoolExecutor中的 ...
- Android多线程研究(1)——线程基础及源码剖析
从今天起我们来看一下Android中的多线程的知识,Android入门容易,但是要完成一个完善的产品却不容易,让我们从线程开始一步步深入Android内部. 一.线程基础回顾 package com. ...
- java 线程池、多线程实战(生产者消费者模型,1 vs 10) 附案例源码
导读 前二天写了一篇<Java 多线程并发编程>点我直达,放国庆,在家闲着没事,继续写剩下的东西,开干! 线程池 为什么要使用线程池 例如web服务器.数据库服务器.文件服务器或邮件服务器 ...
- 小D课堂 - 零基础入门SpringBoot2.X到实战_第9节 SpringBoot2.x整合Redis实战_38、源码编译安装Redis4.x
笔记 2.源码编译安装Redis4.x 简介:使用源码安装Redis4.x和配置外网访问 1.快速安装 https://redis.io/download#installation ...
- java多线程——线程池源码分析(一)
本文首发于cdream的个人博客,点击获得更好的阅读体验! 欢迎转载,转载请注明出处. 通常应用多线程技术时,我们并不会直接创建一个线程,因为系统启动一个新线程的成本是比较高的,涉及与操作系统的交互, ...
- Android多线程:深入分析 Handler机制源码(二)
前言 在Android开发的多线程应用场景中,Handler机制十分常用 接下来,深入分析 Handler机制的源码,希望加深理解 目录 1. Handler 机制简介 定义一套 Android 消息 ...
- C#多线程之旅(4)——APM初探
源码地址:https://github.com/Jackson0714/Threads 原文地址:C#多线程之旅(4)——APM初探 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C# ...
- C#多线程之旅(3)——线程池
v博客前言 先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的,如果没有用好,容易造成很 ...
- C#多线程之旅(1)——介绍和基本概念
原文地址:C#多线程之旅(1)——介绍和基本概念 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C#多线程之旅(2)——创建和开始线程 C#多线程之旅(3)——线程池 C#多线程之旅( ...
随机推荐
- 「CF662C」 Binary Table
「CF662C」 Binary Table 题目链接 题目所给的 \(n\) 很小,于是我们可以考虑这样一种朴素做法:暴力枚举第 \(i\) 行是否翻转,这样每一行的状态就确定了,这时取每一列 \(0 ...
- Automation Framework Design 自动化框架设计思想
从2007年到2017年,十年内自动化测试工具层出不穷,各种工具在运用一段时间之后,各个公司都会有测试架构师对于目前的自动化测试工具进行框架定制设计. 从惠普2007年GDCC推出的的WebDrivi ...
- ASP.NET C# 打包再修改aspx文件报错解决方案
aspx文件最开始: <%@ page language="C#" autoeventwireup="true" inherits="tiddk ...
- element ui table表头动态筛选条件
本文主要实现:根据el-table表格数据自动生成表头筛选条件的方法,可根据表格数据动态调整. el-table表格的表头增加筛选功能,大家平时都是怎么实现的呢?先看看官方文档的例子: 1 <t ...
- Day5 Scanner对象学习.
Scanner对象 Java.until.Scanner 我们可以通过Scanner类来获取用户的输入. 基本语法: Scanner s = new Scanner (System . in) ; 通 ...
- 【JavaWeb】请求和响应Request&Response
请求 请求对象 关于请求 顾名思义,意思就是请求一个"对象" 请求不到的,别想了 请求,就是使用者希望从服务器端索取一些资源,向服务器发出询问.在B/S架构中,就是客户浏览器向服务 ...
- 【Lucas组合数定理】组合-FZU 2020
组合 FZU-2020 题目描述 给出组合数C(n,m), 表示从n个元素中选出m个元素的方案数.例如C(5,2) = 10, C(4,2) = 6.可是当n,m比较大的时候,C(n,m)很大!于是x ...
- 前端基础js(四)
一. js [1] html:用于显示页面 [2] css:用于描述页面的样式 [3] javaScript:用于描述页面的行为 二.js中三大部分内容 [1] 基本语法:函数.对象.事件类型(变量, ...
- idea创建web工程、配置tomcat及基本配置
背景 现在许多人从eclipse转到idea了,小编也不例外.但是刚转初期还是有挺多不适应的,特总结了创建maven的web工程.配置tomcat服务器及基本配置.有了这些配置,上手idea也就跟ec ...
- php获取当前用户ip
function wcs_get_onlineip() { $onlineip = ''; if(getenv('HTTP_CLIENT_IP') && strcasecmp(gete ...