可用來 控制多執行序停止和中斷和Cancel後執行的callback function
建立類別的三種多載Construct
第二種跟第三種多載的建構子參數是設定 多久後會取消Task, 單位為 millisecond(毫秒) 與 TimeSpan
IsCancellationRequested 會在delay時間過後為true,並執行Token中Register的Action。 (Token的Register 可以註冊 工作取消後會執行的動作)
public CancellationTokenSource();
public CancellationTokenSource(int millisecondsDelay);
public CancellationTokenSource(TimeSpan delay);
判斷該 CancellationTokenSource 是否被取消的Property IsCancellationRequested
當被Cancel掉時,該值為true
public bool IsCancellationRequested { get; }
建立具有監聽用途的CancellationTokenSource
該CancellationTokenSource的狀態是否被Cancel 是由 傳入的CancellationToken的狀態來決定,當傳入的任一CancellationToken被Cancel掉時,該CancellationTokenSource也同樣被Cancel掉。
public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2);
public static CancellationTokenSource CreateLinkedTokenSource(params CancellationToken[] tokens);
/// <summary>
/// 建立有連結的CancellationTokenSource
/// 當用來建立的任一CancellationTokenSource被Cancel掉時,該LinkedTokenSource也同樣被Cancel掉
///
/// 測試呼叫 CreateLinkedTokenSource
/// </summary>
public static void CreateLinkedTokenSource()
{
CancellationTokenSource notCancellationTokenSource = new CancellationTokenSource();
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationTokenSource test = CancellationTokenSource.CreateLinkedTokenSource(notCancellationTokenSource.Token, cancellationTokenSource.Token);
cancellationTokenSource.Cancel();
Console.WriteLine($"notCancellationTokenSource類別是否被Cancel了 = {notCancellationTokenSource.IsCancellationRequested}");
Console.WriteLine($"cancellationTokenSource類別是否被Cancel了 = {cancellationTokenSource.IsCancellationRequested}");
Console.WriteLine($"該CancellationTokenSource類別是否被Cancel了 = {test.IsCancellationRequested}");
}
Cancel 掉 CancellationTokenSource
當CancellationTokenSource被Cancel掉時,已經執行中的Task並不會中斷
必須要自行在委派中判斷CancellationTokenSource.IsCancellationRequested or CancellationTokenSource.Token.IsCancellationRequested 是否為true
再處理中斷Task後的動作。
public void Cancel();
public void Cancel(bool throwOnFirstException);
/// <summary>
/// cancel掉Task
///
/// 測試呼叫 Cancel()
/// </summary>
public static void Cancel()
{
stopwatch.Stop();
stopwatch.Reset();
stopwatch.Start();
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken a = new CancellationToken();
Task.Run(() =>
{
while (true)
{
Thread.Sleep(500);
if (cancellationTokenSource.Token.IsCancellationRequested)
{
Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task have canceled!{cancellationTokenSource.IsCancellationRequested}");
return;
}
else
Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task Running!{cancellationTokenSource.IsCancellationRequested}");
}
}, cancellationTokenSource.Token);
Thread.Sleep(5000);
cancellationTokenSource.Cancel();
}
/// <summary>
/// 透過cancellationTokenSource設定Task被cancel掉所要執行的delegate
///
/// 測試呼叫 Cancel() & Cancel(bool throwOnFirstException)
/// 呼叫 Cancel() 會執行 Cancel(false)
/// 該boolean參數 用來判斷當有Register被Cancel掉要執行的動作噴Exception時
/// 若為是,代表直接噴Exception,不管其餘動作是否執行完畢。
/// 若為否,則會執行完其餘Register的動作之後才會噴Exception。
/// </summary>
public static void Cancel_Register()
{
stopwatch.Stop();
stopwatch.Reset();
stopwatch.Start();
try
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
// 註冊的動作是LIFO,最晚註冊的開始執行
cancellationTokenSource.Token.Register(() => Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task Canceled1"));
cancellationTokenSource.Token.Register(() => Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task Canceled2"));
cancellationTokenSource.Token.Register(() => Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task Canceled3"));
cancellationTokenSource.Token.Register(() => Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task Canceled4"));
cancellationTokenSource.Token.Register(() => throw new Exception($"{stopwatch.ElapsedMilliseconds} ms Task Canceled"));
cancellationTokenSource.Token.Register(() => Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task Canceled5"));
Task.Run(() =>
{
while (true)
{
Thread.Sleep(500);
if (!cancellationTokenSource.IsCancellationRequested)
Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task Running!");
}
}, cancellationTokenSource.Token);
Thread.Sleep(5000);
Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms 執行 Task Cancel(false)");
cancellationTokenSource.Cancel();
//cancellationTokenSource.Cancel(true);
}
catch (Exception ex)
{
Console.WriteLine($"發生異常, Error:{ex.Message}");
}
}
執行 Cancel() 也等於 Cancel(false),當Cancel後執行的Register有異常時會執行完所有Register
執行 Cancel(true),當Cancel後執行的Register有發生異常時,其餘的Register則不會執行
定時 Cancel 掉 CancellationTokenSource
有定時功能的Cancel
public void CancelAfter(int millisecondsDelay);
public void CancelAfter(TimeSpan delay);
/// <summary>
/// 透過cancellationTokenSource設定Task幾秒後會cancel掉
///
/// 測試呼叫 CancelAfter(int millisecondsDelay) & CancelAfter(TimeSpan delay)
/// millisecondsDelay 與 delay,代表多久要取消該Task
/// </summary>
public static void CancelAfter()
{
stopwatch.Stop();
stopwatch.Reset();
stopwatch.Start();
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
Task.Run(() =>
{
while (true)
{
Thread.Sleep(500);
if (!cancellationTokenSource.IsCancellationRequested)
Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task Running!");
else
Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task have canceled!");
}
}, cancellationTokenSource.Token);
//cancellationTokenSource.CancelAfter(3000);
cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(5));
}
Dispose CancellationTokenSource
當CancellationTokenSource被Dispose掉,則設定的Register和Cancel Timer都被清除
且只剩IsCancellationRequested可使用,若繼續呼叫Cancel() 則會噴Exception
public void Dispose();
/// <summary>
/// 測試呼叫 Dispose
/// 當CancellationTokenSource被Dispose掉,代表先前設定的Register和Cancel Timer都被清除
/// </summary>
public static void Dispose()
{
stopwatch.Stop();
stopwatch.Reset();
stopwatch.Start();
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
Task.Run(() =>
{
while (true)
{
Thread.Sleep(500);
if (!cancellationTokenSource.IsCancellationRequested)
Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task Running!");
else
Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task have canceled!");
}
}, cancellationTokenSource.Token);
cancellationTokenSource.Token.Register(() => Console.WriteLine($"{stopwatch.ElapsedMilliseconds} ms Task Register"));
// 5秒後Cancel掉Task
cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(5));
// 3秒後dispose掉CancellationTokenSource,清除掉CancelAfter的timer和Register動作
Thread.Sleep(3000);
cancellationTokenSource.Dispose();
// 被dispose掉後除了IsCancellationRequested之外 其餘方法無法再調用,會噴Exception
//cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(2));
}
程式碼 可參考 w4560000/CSharp_Practice/CancellationTokenSourceAPI
轉載請註明來源,若有任何錯誤或表達不清楚的地方,歡迎在下方評論區留言,也可以來信至 leozheng0621@gmail.com
如果文章對您有幫助,歡迎斗內(donate),請我喝杯咖啡