Task中的取消功能
Thread中的取消操作
isStop变量判断thread是否可以退出
bool isStop = false;
Thread thread = new Thread(() =>
{
while (!isStop)
{
Thread.Sleep(100);
Console.WriteLine("当前Thread正在运行。");
}
});
thread.Start();
Thread.Sleep(1000);
isStop = true;
运行结果:thread运行了1秒后停止。
这样存在一个问题,让多个线程操作一个共享变量,在release版本那种会存在潜在bug。bug见笔记二中的release和debug的性能差异。
Task中的取消操作
CancellationTakenSource类远比使用isStop变量要强的多。
使用cancel实现isStop同样的功能
CancellationTokenSource source = new CancellationTokenSource();
var task = Task.Factory.StartNew(() =>
{
while (!source.IsCancellationRequested)
{
Thread.Sleep(100);
Console.WriteLine("当前Thread正在运行。");
}
}, source.Token) ;
Thread.Sleep(1000);
source.Cancel();
运行结果:与使用isStop结果一样
那么CancellationTakenSource类比使用isStop变量要强在哪里?
a. 当任务取消的时候,若希望有一个函数能被触发,这个触发可以做一些资源清理,又或者是更新数据库信息。当task被取消的同时就会执行register中的回调函数。
CancellationTokenSource source = new CancellationTokenSource();
source.Token.Register(() =>
{
//如果当前的Source被取消,此函数会执行
Console.WriteLine("如果当前source被取消,现在可以做资源清理了。");
});
var task = Task.Factory.StartNew(() =>
{
while (!source.IsCancellationRequested)
{
Thread.Sleep(100);
Console.WriteLine("当前Thread={0},正在运行。", Thread.CurrentThread.ManagedThreadId);
}
}, source.Token);
执行结果:
b. 延时取消。
如果想N秒后自动取消,例如调用webservice接口,如果很久没响应,应该设置若干秒后自动取消。
方法一:CancelAfter
source.CancelAfter(new TimeSpan(0,0,0,1));
方法二:在CancellationTokenSource的构造函数中设置时间
CancellationTokenSource source = new CancellationTokenSource(1000);
c. 取消的组合
var combineSource = CancellationTokenSource.CreateLinkedTokenSource(source1.Token, source2.Token);
Console.WriteLine("s1 = {0}, s2 = {1}, s = {2}",source1.IsCancellationRequested,
source2.IsCancellationRequested,combineSource.IsCancellationRequested);
输出结果:s1 = True, s2 = False, s = True。
可以看出 s = s1 && s2
d. ThrowIfCancellationRequested
如果一个任务被取消,会抛出一个异常。
CancellationTokenSource source = new CancellationTokenSource();
var task = Task.Factory.StartNew(() =>
{
while (true)
{
try
{
source.Token.ThrowIfCancellationRequested();
}catch(Exception)
{
//do something
}
}
}, source.Token);