国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
《CLR via C#》讀書筆記

《CLR via C#》讀書筆記-.NET多線程(四)

作者:zlbcdn

協(xié)作式取消
協(xié)作式取消其英文為: cooperative cancellation model。在26.4節(jié)中只是很簡單的介紹了通過CancellationTokenSource來終結(jié)一個異步操作或長時間執(zhí)行的同步操作。沒有具體的分析和說明為什么要這樣用。因為終結(jié)一個異步操作的方法有很多,可以使用最簡單的truefalse變量結(jié)束異步操作。因此本次詳細整理CLR的在線程取消的模式。本文參考了MSDN及其他網(wǎng)友的相關(guān)資料,具體的引用會在文章的尾端。
從.NET4開始,.NET Framework才為異步或需長時間執(zhí)行的同步操作提供了協(xié)作取消模式。通常使用的有兩個“東西“,一個是CancellationTokenSource,另一個是struct:CancellationToken。前者是取消請求的發(fā)起者,而后者是消息請求的監(jiān)聽者。就像量子世界中的量子糾纏一樣,一個是根據(jù)現(xiàn)場的環(huán)境做出相應(yīng)的響應(yīng),而另一個會立刻做出反應(yīng)。CancellationTokenSource與CancellationToken就是這樣的一個狀態(tài)。
協(xié)作式取消的使用
協(xié)作式取消的使用步驟如下:
1、創(chuàng)建CancellationTokenSource實例
2、使用CancellationTokenSource實例的Token屬性,獲取CancellationToken,并將其傳至Task或線程的相關(guān)方法中
3、在task或thread中提供根據(jù)CancellationToken.IsCancellationRequested屬性值進行判定是否應(yīng)該停止操作的機制
4、在程序中調(diào)用CancellationTokenSource實例的cancel方法
這兒有一篇文章,是使用CancellationTokenSource的具體例子。.Net 4.5中通過CancellationTokenSource實現(xiàn)對超時任務(wù)的取消
CancellationTokenSource
1、定義
CancellationTokenSource類的定義如下:

[ComVisibleAttribute(false)][HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true,     ExternalThreading = true)]public class CancellationTokenSource : IDisposable
  • 1
  • 2
  • 3
  • 4

因本類實現(xiàn)了IDisposable的方法,因此在用完時需調(diào)用其dispose方法,或者是使用using
2、CancellationTokenSource與CancellationToken的關(guān)系
兩者的關(guān)系如圖所示:


通過這張圖,可得出:
1、不同的操作使用相同的CancellationTokenSource實例,就可以達到一次調(diào)用取消多個操作的目的。
2、CancellationToken為什么會是struct,而不是類
3、其他說明
1、除了CancellationTokenSource與CancellationToken之外,還有一個OperationCanceledException異常類,這個overload的異常類接受Token作為參數(shù),因此在判斷具體異常時,可使用本類
4、代碼說明
代碼如下:

using System;using System.Threading;public class Example{   public static void Main()   {      // Create the token source.      CancellationTokenSource cts = new CancellationTokenSource();      // Pass the token to the cancelable operation.      ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomeWork), cts.Token);      Thread.Sleep(2500);      // Request cancellation.      cts.Cancel();      Console.WriteLine("Cancellation set in token source...");      Thread.Sleep(2500);      // Cancellation should have happened, so call Dispose.      cts.Dispose();   }   // Thread 2: The listener   static void DoSomeWork(object obj)   {      CancellationToken token = (CancellationToken)obj;      for (int i = 0; i < 100000; i++) {         if (token.IsCancellationRequested)         {            Console.WriteLine("In iteration {0}, cancellation has been requested...",                              i + 1);            // Perform cleanup if necessary.            //...            // Terminate the operation.            break;         }         // Simulate some work.         Thread.SpinWait(500000);      }   }}// The example displays output like the following://       Cancellation set in token source...//       In iteration 1430, cancellation has been requested...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

以上方法使用的系統(tǒng)遺留方式,但是希望停止一個task時,參見如下:How to: Cancel a Task and Its Children
操作取消與對象取消(Operation Cancellation Versus Object Cancellation)
在協(xié)作式取消操作中,通常都是在方法中通過判斷Token的IsCancellationRequested屬性,然后根據(jù)這個屬性的值對操作(或方法)進行相應(yīng)的處理。因此,常用的協(xié)作式取消模式就是Operation Cancellation。PS.Token的IsCancellationRequested只能被設(shè)置一次,即當(dāng)該屬性被設(shè)置為true時,其不可能再被設(shè)為false,不能重復(fù)利用。另外,Token在被“用過”后,不能重復(fù)使用該對象。即,CancellationTokenSource對象只能使用一次,若希望重復(fù)使用,需要在每次使用時,創(chuàng)建新的對象。
除了操作取消之外,還有另外一種情況,我希望當(dāng)CancellationTokenSource實例調(diào)用cancel方法時,調(diào)用某個實例中的某個方法。而這個方法內(nèi)部沒有CancellationToken對象。這個時候可以使用CancellationTokenSource的Register方法。
方法的定義如下:

public CancellationTokenRegistration Register(Action callback)
  • 1

其中Action是.NET內(nèi)部的自定義的委托,其具體的定義:

public delegate void Action()
  • 1

可使用CancellationToken.Register方法完成對實例中方法的調(diào)用。如下有一個例子:

using System;using System.Threading;class CancelableObject{   public string id;   public CancelableObject(string id)   {      this.id = id;   }   public void Cancel()    {       Console.WriteLine("Object {0} Cancel callback", id);      // Perform object cancellation here.   }}public class Example{   public static void Main()   {      CancellationTokenSource cts = new CancellationTokenSource();      CancellationToken token = cts.Token;      // User defined Class with its own method for cancellation      var obj1 = new CancelableObject("1");      var obj2 = new CancelableObject("2");      var obj3 = new CancelableObject("3");      // Register the object's cancel method with the token's      // cancellation request.      token.Register(() => obj1.Cancel());      token.Register(() => obj2.Cancel());      token.Register(() => obj3.Cancel());      // Request cancellation on the token.      cts.Cancel();      // Call Dispose when we're done with the CancellationTokenSource.      cts.Dispose();   }}// The example displays the following output://       Object 3 Cancel callback//       Object 2 Cancel callback//       Object 1 Cancel callback
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

取消操作的監(jiān)聽與響應(yīng)方式
在一般情況下,在方法內(nèi)部使用使用Token.IsCancellationRequested屬性判斷其值,然后根據(jù)其值進行后續(xù)操作。這種模式可適應(yīng)大部分的情況。但是有些情況需要額外的處理方式。
特別是當(dāng)用戶在使用一些外部的library代碼時,上面提到的方式可能效果不好,更好的方法就是調(diào)用Token的方法 ThrowIfCancellationRequested(),讓它拋出異常OperationCanceledException,外部的Library截住異常,然后通過判斷異常的Token的相關(guān)屬性值,再進行相應(yīng)的處理。
ThrowIfCancellationRequested()的方法相當(dāng)于:

    if (token.IsCancellationRequested)         throw new OperationCanceledException(token);
  • 1
  • 2

因此在使用本方法時,通常的用法是(假設(shè)自己正在寫的代碼會被編譯為Library,供其他人調(diào)用,則自己寫的代碼應(yīng)該是這樣的):

if(!token.IsCancellationRequested){    //這兒正常的操作,    //未被取消時,正常的代碼和邏輯操作實現(xiàn)}else{    //代表用戶進行了取消操作    //可以進行一些日志記錄    //注銷正在使用的資源    //然后就需要調(diào)用方法    token.ThrowIfCancellationRequested();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

當(dāng)別人使用Library時,需要在catch塊中監(jiān)聽OperationCanceledException異常,代碼如下:

try{    //調(diào)用Library的方法    library.doSomethingMethod();}catch(OperationCanceledException e1){    //捕獲這個異常,代表是用戶正常取消本操作,因此在這兒需要處理釋放資源之類的事情    xxx.dispose();}catch(exception e2){    //其他異常的具體處理方法}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

以上是處理或?qū)懝﹦e人使用的Library或DLL時應(yīng)該遵循的方法。
在方法內(nèi)部進行處理相關(guān)流程時,對于監(jiān)聽用戶是否進行了取消操作,有如下的幾種方式:
1.輪詢式監(jiān)聽(Listening by Polling)
這種方法是最常用的,也是上面提到的,樣例如下:

static void NestedLoops(Rectangle rect, CancellationToken token){   for (int x = 0; x < rect.columns && !token.IsCancellationRequested; x++) {      for (int y = 0; y < rect.rows; y++) {         // Simulating work.         Thread.SpinWait(5000);         Console.Write("{0},{1} ", x, y);      }      // Assume that we know that the inner loop is very fast.      // Therefore, checking once per row is sufficient.      //就是下面的這句,通過for循環(huán)內(nèi)部的輪詢,去判斷IsCancellationRequested屬性值,從而去決定做其他的事情      if (token.IsCancellationRequested) {         // Cleanup or undo here if necessary...         Console.WriteLine("\r\nCancelling after row {0}.", x);         Console.WriteLine("Press any key to exit.");         // then...         break;         // ...or, if using Task:         //若使用Task時,調(diào)用ThrowIfCancellationRequested方法,使其拋出異常         // token.ThrowIfCancellationRequested();      }   }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

2.通過回調(diào)方法處理取消操作(Listening by Registering a Callback)
在比較復(fù)雜的情況下,可以使用register方法,注冊或登記取消回調(diào)方法。如下所示:

using System;using System.Net;using System.Threading;using System.Threading.Tasks;class CancelWithCallback{   static void Main()   {      var cts = new CancellationTokenSource();      var token = cts.Token;      // Start cancelable task.      // 這兒使用了一個Task,Task的使用和具體內(nèi)容可參見多線程(五)      Task t = Task.Run( () => {                    WebClient wc = new WebClient();                    // Create an event handler to receive the result.                    wc.DownloadStringCompleted += (obj, e) => {                               // Check status of WebClient, not external token.                               if (!e.Cancelled) {                                  Console.WriteLine("The download has completed:\n");                                  Console.WriteLine(e.Result + "\n\nPress any key.");                               }                               else {                                  Console.WriteLine("The download was canceled.");                               }                    };                    // Do not initiate download if the external token has already been canceled.                    // 當(dāng)沒有收到取消消息時,則進行相關(guān)的下載。                    // 并且在初始化時,進行了回調(diào)方法的登記,因此,當(dāng)token收到取消的方法時,則調(diào)用wc.CancelAsync()                    if (!token.IsCancellationRequested) {                       // Register the callback to a method that can unblock.                       using (CancellationTokenRegistration ctr = token.Register(() => wc.CancelAsync()))                       {                          Console.WriteLine("Starting request\n");                          wc.DownloadStringAsync(new Uri("http://www.contoso.com"));                       }                    }               }, token);      Console.WriteLine("Press 'c' to cancel.\n");      char ch = Console.ReadKey().KeyChar;      Console.WriteLine();      if (ch == 'c')         cts.Cancel();      Console.WriteLine("Press any key to exit.");      Console.ReadKey();      cts.Dispose();   }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

在使用register方法時,有幾個注意事項:
1、callback方法盡量要快!不要阻礙線程!因此Cancel方法要等到callback方法結(jié)束后才返回
2、callback方法要盡量不要再使用多線程。
3.多對象關(guān)聯(lián)
可通過CancellationTokenSource的CreateLinkedTokenSource方法鏈接多個對象,從而形成一個新的CancellationTokenSource對象
鏈接中的任何一個對象使用了cancel方法,這個新的“鏈?zhǔn)健睂ο笠矔蝗∠?。如下?/p>

var cts1=new CancellationTokenSource();cts1.register(()=>Console.writeline("cts1被取消"));var cts2=new CancellationTokenSource();cts2.register(()=>Console.writeline("cts2被取消"));var linkcts=CancellationTokenSource.CreateLinkedTokenSource(cts1,cts2);linkcts.register(()=>Console.writeline("LinkCts被取消"));cts2.cancel();//其輸出結(jié)果如下://LinkCts被取消//cts2被取消
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

寫在本節(jié)學(xué)習(xí)最后
1、若自己的程序需要封裝為library,供其他人調(diào)用,則需要做好兩點:1、方法需要接受一個token作為參數(shù);2、需要較好的處理OperationCanceledException異常。
2、本節(jié)學(xué)習(xí)主要是結(jié)合:《CLR via C#》、MSDN的官網(wǎng)具體的網(wǎng)址在這兒, 以及網(wǎng)友的相關(guān)的文章。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
C# 異步編程
C# 使用 CancellationTokenSource 終止線程
(轉(zhuǎn))改善C#程序的建議9:使用Task代替ThreadPool和Thread
C# 探秘線程如何終止
C# 使用CancellationTokenSource取消多線程
C# Task 用法
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服