《CLR via C#》之线程处理——协作式取消和超时
《CLR via C#》之线程处理——协作式取消和超时
协作式取消和超时
创建协作式取消步骤:
- 首先创建一个System.Threading.CancellationTokenSource对象。
public sealed class CancellationTokenSource : IDisposable
{
// 一个引用类型
public void Dispose(); // 释放资源(比如WaitHandle)
public Boolean IsCancellationRequested { get; }
public CancellationToken Token { get; }//通过这个属性获得Token并传递给操作。
public void Cancel(); // 内部调用Cancel并传递false
public void Cancel(Boolean throwOnFirstException);
...
}
- 通过CancellationTokenSource.Token属性获得一个或多个CancellationToken,并传递给操作。
public struct CancellationToken
{
// 一个值类型
public static CancellationToken None { get; }
public Boolean IsCancellationRequested{ get; } // 由非通过Task调用的操作调用
public void ThrowIfCancellationRequested(); // 由通过Task调用的操作调用
//CancellationTokenSource 取消时,WaitHandle 会收到信号
public WaitHandle WaitHandle { get; }
public Boolean CanBeCanceled { get; } // 很少使用
public CancellationTokenRegistration Register(Action<Object> callback, Object state,
Boolean useSynchronizationContex); // 未列出更简单的重载版本
}
- 需要取消的方法中定期查询IsCancellationRequest属性。
internal static class CancellationDemo
{
public static void Go()
{
CancellationTokenSource cts = new CancellationTokenSource();
cts.Token.Register(() => Console.WriteLine("cancel callbace!!!"));
var restration = cts.Token.Register(o => Console.WriteLine("Cancel callback{0}!!!", o), 5, true);
restration.Dispose();
ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 1000));
Console.WriteLine("Press Enter to cancel");
Console.ReadLine();
cts.Cancel();
Console.ReadLine();
}
private static void Count(CancellationToken token, Int32 countTo)
{
for (int count = 0; count < countTo; count++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Count is cancelled");
break;
}
Console.WriteLine(count);
Thread.Sleep(200);
}
Console.WriteLine("Count is done");
}
}
PS:如果要执行一个不允许被取消的操作,可以向操作传递CancellationTokenSource.None属性。
- 如果需要,可以调用CancellationToken的Register方法,注册取消时的CallBack。可以通过该方法的返回值CallcellationTakenRegistration,调用它的Dispose方法删除注册的回调函数。
- 还可以链接另一组CancellationTokenSource来新建一个CancellationTokenSource对象。
var cts1 = new CancellationTokenSource();
cts1.Token.Register(() => Console.WriteLine("cts1 cancelled"));
var cts2 = new CancellationTokenSource();
cts2.Token.Register(() => Console.WriteLine("cts2 canceled"));
//创建一个新的,它在cts1或cts2取消时取消
var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);
linkedCts.Token.Register(() => Console.WriteLine("linkedCts canceled"));
- 还可以通过CancellationTokenSource的构造器或调用CancelAfter来指定延时时间,到时自动取消。
public sealed class CancellationTokenSource : IDisposable
{
public CancellationTokenSource(Int32 millisecondsDelay);
public CancellationTokenSource(TimeSpan delay);
public void CancelAfter(Int32 millisecondsDelay);
public void CancelAfter(TimeSpan delay);
...
}