C#如何优雅地取消一个流程(非Thread.Abort方法)
2021-01-14 14:14
标签:this sync 方法 let llb ret 修改 main 业务 我们使用 Thread.Abort() 来中止一个包裹着某个流程的线程,虽然 C# 并不会像 Thread.Suspend() 提示过时。但是在使用 Thread.Abort() 的时候,确实存在很多的问题: 1. 该方式中止线程是通过在线程执行的时候抛出 ThreadAbortException 异常来实现的。这边抛出的 ThreadAbortException 异常,不一定可以被局部的程序异常处理程序准确地捕获,而会被抛出在全局,需要通过 AppDomain.CurrentDomain.UnhandledException 来进行捕获处理; 注:关于 AppDomain.CurrentDomain.UnhandledException 的使用,请看下面的文章: 《关于C# 全局异常捕获》 2. 不能确定线程中止的时间和在中止之前所执行到的位置。总之,它取消线程是一个队列的处理方式,所以处理不是被立即响应的,而是要等一会,这就导致了程序的中止时间和在中止之前执行到了哪里都是未知的; 答:有。分析:中止一个流程,我们一定要向这个流程发送一个中止的信号,当这个流程获得这个信号的时候,立刻中断之后的操作并返回。因此,我们可以分析出来,这个流程在工作的时候,起码要有两个角色: 综上,我们可以考虑使用委托的异步调用来实现,如果要取消就使用轮序信号来实现。 答:要注意的是在发送消息之后,更新、判断取消状态的线程异步问题。所以代码要上锁,如下: - 业务逻辑: - 取消操作: 由于我们无法知道,是 Cancel() 方法先修改 isCancel 标志位的值,还是 LongTimeMethod() 业务方法先判断 isCancel 为 false 并执行业务逻辑代码。所以程序在为后者的情况下,要在后执行的 Cancel() 方法中添加用于直接完成了业务逻辑的补救操作。 - 窗体程序就是打开一个窗体,名字叫 " DemoForm.exe " 的程序 - 实现异步委托调用的类,也就是业务逻辑类 LongTimeEx.cs,代码如下: - 上端的调用代码: 下载地址 C#如何优雅地取消一个流程(非Thread.Abort方法) 标签:this sync 方法 let llb ret 修改 main 业务 原文地址:https://www.cnblogs.com/Jeffrey-Chou/p/12256561.html一. Thread.Abort() 的缺点
二. 代替方法
三. 代码
public class LongTime
{
public bool isComplete = false;
public bool isCancel = false;
public bool isSuccess = false;
private object asynObject = new object();
private bool LongTimeMethod()
{
lock (asynObject)
{
if(this.isCancel)
{
//如果取消了要做什么操作
}
Thread.Sleep(10 * 1000);
return false;
}
}
public void Test()
{
Console.WriteLine("开始...");
//异步执行体
AsyncCallback callback = (r) =>
{
this.isComplete = r.IsCompleted;
};
IAsyncResult result = ((Action)(() =>
{
this.isSuccess = LongTimeMethod();
}))
.BeginInvoke(callback, null);
//执行表征体
while (!isCancel && !result.IsCompleted)
{
Thread.Sleep(50);
}
Console.WriteLine(this.isCancel ? "取消" : "完成");
}
/*
* ?重要?
* 会处在一个异步的线程中,如果这里面的内容与LongTimeMethod方法中的内容有冲突
* 那么会导致线程先后的次序的问题
* 所以这边要加上lock
*/
public void Cancel()
{
lock (asynObject)
{
this.isCancel = true;
//如果执行完成了业务逻辑之后的补救操作
}
}
}
LongTime longTime = new LongTime();
//随机取消
Thread thread = new Thread(() =>
{
Thread.Sleep(2000);
if ((new Random()).Next() % 2 == 0)
{
longTime.Cancel();
}
});
thread.Start();
//开始测试
longTime.Test();
Console.ReadKey();
四. 要点分析
private bool LongTimeMethod()
{
lock (asynObject)
{
if(this.isCancel)
{
//如果取消了要做什么操作
}
Thread.Sleep(10 * 1000);
return false;
}
}
public void Cancel()
{
lock (asynObject)
{
this.isCancel = true;
//如果执行完成了业务逻辑之后的补救操作
}
}
public class LongTimeEx
{
public static bool isComplete = true;
public static bool isCancel = true;
public static bool isSuccess = false;
private static object asynObject = new object();
private bool LongTimeMethod()
{
lock (asynObject)
{
if (isCancel)
{
return false;
}
using (Process process = new Process())
{
process.StartInfo.FileName = "DemoForm.exe";
process.Start();
}
return true;
}
}
public void Test()
{
Console.WriteLine("开始...");
//判断一下上一个是不是已经结束
while (!LongTimeEx.isComplete || !LongTimeEx.isCancel)
{
Thread.Sleep(50);
}
//由于修改为了静态的变量
//导致这边每次都要重新刷新
isComplete = false;
isCancel = false;
//异步执行体
AsyncCallback callback = (r) =>
{
isComplete = r.IsCompleted;
};
IAsyncResult result = ((Action)(() =>
{
isSuccess = LongTimeMethod();
}))
.BeginInvoke(callback, null);
//执行表征体
while (!isCancel && !result.IsCompleted)
{
Thread.Sleep(50);
}
}
public void Cancel()
{
lock(asynObject)
{
isCancel = true;
//取消一下启动的进程
Process[] process = Process.GetProcessesByName("DemoForm");
if(process.Count()>0)
{
foreach(Process p in process)
{
p.Kill();
}
}
}
}
}
LongTimeEx longTimeEx = new LongTimeEx();
longTimeEx.Test();
longTimeEx.Cancel();
longTimeEx.Test();
Console.ReadKey();
五. 示例代码下载
文章标题:C#如何优雅地取消一个流程(非Thread.Abort方法)
文章链接:http://soscw.com/index.php/essay/41818.html