Microsoft .Net Framework 提供了一个标准的取消操作的模式。这个模式是协作式的,意味着你想取消的操作必须显示地支持取消。
CLR为我们提供了两个类:
System.Threading.CancellationTokenSource
System.Threading.CancellationToken
CancellationToken实例是一个轻量级的值类型,因为它包含单个私有字段:CancellationTokenSource的一个引用。在一个计算限制操作的循环中,可以定时调用CancellationToken的IsCancellationRequested属性,了解循环是否应该提前终止,进而终止计算机限制的操作。
我附上我常用代码:
CancellationTokenSource cancel=new CancellationTokenSource(); Task.Factory.StartNew(() => { while (!cancel.IsCancellationRequested) { //do something } }, cancel.Token);// cancel.Token->CancellationToken //取消操作 cancel.Cancel(); cancel.Dispose(); cancel=null;
如果用到线程池,也可以使用这个类
public void main() { var cancel=new CancellationTokenSource(); ThreadPool.QueueUserWorkItem(_ => { while (!cancel.IsCancellationRequested) { //do something } }); Thread.Sleep(10 * 1000);//为了让循环多做些时间 cancel.Cancel(); cancel.Dispose(); }
这个类还有一个很好的地方,可以在自定义回调函数,在调用Cancel方法的时候使用。这个我们需要用到CancellationToken里面的Register方法(也就是new CancellationTokenSource().Token.Register(()=>{})),并且可以给一个Token多次注册,按照倒序执行。
var cancel = new CancellationTokenSource();
cancel.Token.Register(() =>
{
MessageBox.Show("Register3");
});
cancel.Token.Register(() =>
{
MessageBox.Show("Register");
});
cancel.Token.Register(() =>
{
MessageBox.Show("Register1");
});
cancel.Token.Register(() =>
{
MessageBox.Show("Register2");
});
弹出顺序:Register2,Register1,Register,Register3
如果想注销注册的回调函数,需要用到CancellationTokenRegistration(这个在调用Register的时候就会返回),附代码:
CancellationTokenRegistration registration = cancel.Token.Register(() => { MessageBox.Show("Register2"); }); registration.Dispose();//这里可以取消
取消以后再跑,就只会弹出另外三个,还是倒序。
最后,可通过链接另一组CancellationTokenSource来新建一个CancellationTokenSource对象,任何链接的CancellationTokenSource被取消,这个新的CancellationTokenSource对象就会自动被取消,附代码:
public static void Go() { var cts1 = new CancellationTokenSource(); cts1.Token.Register(() => Console.WriteLine("cts1 canceled")); var cts2 = new CancellationTokenSource(); cts2.Token.Register(() => Console.WriteLine("cts2 canceled")); var linkedcts = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token); linkedcts.Token.Register(() => Console.WriteLine("linkedcts canceled")); cts2.Cancel(); Console.WriteLine("cts1:{0} cts2:{1} linkedcts:{2}", cts1.IsCancellationRequested, cts2.IsCancellationRequested, linkedcts.IsCancellationRequested); }
由于cts2对象被取消了,所以linkedcts自动被取消,这里CancellationTokenSource.CreateLinkedTokenSource 有一个重载是params CancellationToken[], 理论上说,无论加多少个CancellationToken对象都是可以的。