第七节:利用CancellationTokenSource实现任务取消和利用CancellationToken类检测取消异常。
一. 傳統的線程取消
? 所謂的線程取消,就是線程正在執行的過程中取消線程任務。
? 傳統的線程取消,是通過一個變量來控制,但是這種方式,在release模式下,被優化從cpu高速緩存中讀取,而不是從內存中讀取,會造成主線程無法執行這一個bug。
1 {2 var isStop = false;3 var thread = new Thread(() =>4 {5 while (!isStop)6 {7 Thread.Sleep(100);8 Console.WriteLine("當前thread={0} 正在運行", Thread.CurrentThread.ManagedThreadId);9 } 10 }); 11 thread.Start(); 12 Thread.Sleep(1000); 13 isStop = true; 14 }?
PS:?通過上面的代碼看可以看出來,傳統模式的線程取消,在排除release模式bug的情況下,局限性還是很明顯的。比如:當子線程任務取消的那一刻,我想執行另外一項任務;我想延時取消一個線程任務;線程取消的時候拋異常。
上述這幾種情況,我們都要借助單獨的類來處理。
?
二.?CancellationTokenSource實現任務取消?
1.?取消任務的同時觸發一個函數
? 利用Cancel方法、Register注冊、source.Token標記取消位來實現。
{CancellationTokenSource source = new CancellationTokenSource();//注冊一個線程取消后執行的邏輯source.Token.Register(() =>{//這里執行線程被取消后的業務邏輯.Console.WriteLine("-------------我是線程被取消后的業務邏輯---------------------");});Task.Run(() =>{while (!source.IsCancellationRequested){Thread.Sleep(100);Console.WriteLine("當前thread={0} 正在運行", Thread.CurrentThread.ManagedThreadId);}}, source.Token);Thread.Sleep(2000);source.Cancel();}2. 延時取消
線程的延時取消有兩種方式:
方案一:CancelAfter方法。
1 #region 方案一:CancelAfter方法2 {3 CancellationTokenSource source = new CancellationTokenSource();4 //注冊一個線程取消后執行的邏輯5 source.Token.Register(() =>6 {7 //這里執行線程被取消后的業務邏輯.8 Console.WriteLine("-------------我是線程被取消后的業務邏輯---------------------");9 }); 10 11 Task.Run(() => 12 { 13 while (!source.IsCancellationRequested) 14 { 15 Thread.Sleep(100); 16 Console.WriteLine("當前thread={0} 正在運行", Thread.CurrentThread.ManagedThreadId); 17 } 18 }, source.Token); 19 20 Thread.Sleep(2000); 21 //4s后自動取消 22 source.CancelAfter(new TimeSpan(0, 0, 0, 4)); 23 } 24 #endregion方案二:CancellationTokenSource構造函數(不再需要Cancel方法了)。
1 {2 //4s后自動取消3 CancellationTokenSource source = new CancellationTokenSource(4000);4 //注冊一個線程取消后執行的邏輯5 source.Token.Register(() =>6 {7 //這里執行線程被取消后的業務邏輯.8 Console.WriteLine("-------------我是線程被取消后的業務邏輯---------------------");9 }); 10 11 Task.Run(() => 12 { 13 while (!source.IsCancellationRequested) 14 { 15 Thread.Sleep(100); 16 Console.WriteLine("當前thread={0} 正在運行", Thread.CurrentThread.ManagedThreadId); 17 } 18 }, source.Token); 19 20 Thread.Sleep(2000); 21 }?
3. 組合取消
?利用CreateLinkedTokenSource構建CancellationTokenSource的組合體,其中任何一個體取消,則組合體就取消。?
{CancellationTokenSource source1 = new CancellationTokenSource();//source1.Cancel();CancellationTokenSource source2 = new CancellationTokenSource();source2.Cancel();var combineSource = CancellationTokenSource.CreateLinkedTokenSource(source1.Token, source2.Token);Console.WriteLine("s1={0} s2={1} s3={2}", source1.IsCancellationRequested,source2.IsCancellationRequested,combineSource.IsCancellationRequested);}上述代碼,source1和source2中的任何一個取消,combineSource就會被取消。
?
三.?CancellationToken類監控取消
? CancellationToken類下ThrowIfCancellationRequested屬性,等價于if (XXX.IsCancellationRequested){throw new Exception("報錯了");}
? 只要取消就報錯。
1 {2 CancellationTokenSource source1 = new CancellationTokenSource();3 CancellationTokenSource source2 = new CancellationTokenSource();4 var combineSource = CancellationTokenSource.CreateLinkedTokenSource(source1.Token, source2.Token);5 source1.Cancel();6 7 //if (combineSource.IsCancellationRequested)8 //{9 // throw new Exception("報錯了"); 10 //} 11 12 //等價于上面那句話 13 try 14 { 15 combineSource.Token.ThrowIfCancellationRequested(); 16 } 17 catch (Exception) 18 { 19 Console.WriteLine("報錯了"); 20 } 21 22 23 Console.WriteLine("s1={0} s2={1} s3={2}", source1.IsCancellationRequested, 24 source2.IsCancellationRequested, 25 combineSource.IsCancellationRequested); 26 } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的第七节:利用CancellationTokenSource实现任务取消和利用CancellationToken类检测取消异常。的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓之光 小米12 Ultra入网:年度
- 下一篇: 第十五节:深入理解async和await