【C#】線程協作式取消


Microsoft .Net Framework 提供了一個標准的取消操作的模式。這個模式是協作式的,意味着你想取消的操作必須顯示地支持取消。

CLR為我們提供了兩個類:

  System.Threading.CancellationTokenSource

  System.Threading.CancellationToken

CancellationToken實例是一個輕量級的值類型,因為它包含單個私有字段:CancellationTokenSource的一個引用。在一個計算限制操作的循環中,可以定時調用CancellationToken的IsCancellationRequested屬性,了解循環是否應該提前終止,進而終止計算機限制的操作。

   我附上我常用代碼:

CancellationTokenSource cancel=new CancellationTokenSource();

    Task.Factory.StartNew(() =>
        {
            while (!cancel.IsCancellationRequested)
            {
                 //do something
            }
        }, cancel.Token);// cancel.Token->CancellationToken
  
     //取消操作
     cancel.Cancel();
     cancel.Dispose();
     cancel=null; 

如果用到線程池,也可以使用這個類

  public void main()
  {
         var cancel=new CancellationTokenSource();
         ThreadPool.QueueUserWorkItem(_ =>
            {
                while (!cancel.IsCancellationRequested)
                {
                    //do something
                }
            });

            Thread.Sleep(10 * 1000);//為了讓循環多做些時間
            cancel.Cancel();
            cancel.Dispose();
  }

這個類還有一個很好的地方,可以在自定義回調函數,在調用Cancel方法的時候使用。這個我們需要用到CancellationToken里面的Register方法(也就是new CancellationTokenSource().Token.Register(()=>{})),並且可以給一個Token多次注冊,按照倒序執行。

 

 var cancel = new CancellationTokenSource(); cancel.Token.Register(() => { MessageBox.Show("Register3"); }); cancel.Token.Register(() => { MessageBox.Show("Register"); }); cancel.Token.Register(() => { MessageBox.Show("Register1"); }); cancel.Token.Register(() => { MessageBox.Show("Register2"); });

 彈出順序:Register2Register1,Register,Register3

如果想注銷注冊的回調函數,需要用到CancellationTokenRegistration(這個在調用Register的時候就會返回),附代碼:

        CancellationTokenRegistration registration = cancel.Token.Register(() =>
             {
                 MessageBox.Show("Register2");
             });
            registration.Dispose();//這里可以取消    

取消以后再跑,就只會彈出另外三個,還是倒序。

最后,可通過鏈接另一組CancellationTokenSource來新建一個CancellationTokenSource對象,任何鏈接的CancellationTokenSource被取消,這個新的CancellationTokenSource對象就會自動被取消,附代碼:

  public static void Go()
        {
            var cts1 = new CancellationTokenSource();
            cts1.Token.Register(() => Console.WriteLine("cts1 canceled"));

            var cts2 = new CancellationTokenSource();
            cts2.Token.Register(() => Console.WriteLine("cts2 canceled"));

            var linkedcts = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);
            linkedcts.Token.Register(() => Console.WriteLine("linkedcts canceled"));

            cts2.Cancel();

            Console.WriteLine("cts1:{0}  cts2:{1}  linkedcts:{2}",
                cts1.IsCancellationRequested, cts2.IsCancellationRequested, linkedcts.IsCancellationRequested);
        }

由於cts2對象被取消了,所以linkedcts自動被取消,這里CancellationTokenSource.CreateLinkedTokenSource 有一個重載是params CancellationToken[], 理論上說,無論加多少個CancellationToken對象都是可以的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM