乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      《CLR via C#》讀書筆記

       牛人的尾巴 2016-12-13

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

      作者:zlbcdn

      協(xié)作式取消
      協(xié)作式取消其英文為: cooperative cancellation model。在26.4節(jié)中只是很簡單的介紹了通過CancellationTokenSource來終結(jié)一個異步操作或長時間執(zhí)行的同步操作。沒有具體的分析和說明為什么要這樣用。因為終結(jié)一個異步操作的方法有很多,可以使用最簡單的truefalse變量結(jié)束異步操作。因此本次詳細(xì)整理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)系如圖所示:
      兩者的關(guān)系
      通過這張圖,可得出:
      1、不同的操作使用相同的CancellationTokenSource實例,就可以達(dá)到一次調(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."));
                             }
                          }
                     }, 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ǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多