簡體   English   中英

如何使用 CancellationToken 屬性?

[英]How to use the CancellationToken property?

與前面的RulyCanceler 類代碼相比,我想使用CancellationTokenSource運行代碼。

我如何像Cancellation Tokens 中提到的那樣使用它,即不拋出/捕獲異常? 我可以使用IsCancellationRequested屬性嗎?

我試圖像這樣使用它:

cancelToken.ThrowIfCancellationRequested();

try
{
  new Thread(() => Work(cancelSource.Token)).Start();
}
catch (OperationCanceledException)
{
  Console.WriteLine("Canceled!");
}

但這在cancelToken.ThrowIfCancellationRequested();上給出了一個運行時錯誤cancelToken.ThrowIfCancellationRequested(); 在方法Work(CancellationToken cancelToken)

System.OperationCanceledException was unhandled
  Message=The operation was canceled.
  Source=mscorlib
  StackTrace:
       at System.Threading.CancellationToken.ThrowIfCancellationRequested()
       at _7CancellationTokens.Token.Work(CancellationToken cancelToken) in C:\xxx\Token.cs:line 33
       at _7CancellationTokens.Token.<>c__DisplayClass1.<Main>b__0() in C:\xxx\Token.cs:line 22
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:

我成功運行的代碼在新線程中捕獲了 OperationCanceledException:

using System;
using System.Threading;
namespace _7CancellationTokens
{
  internal class Token
  {
    private static void Main()
    {
      var cancelSource = new CancellationTokenSource();
      new Thread(() =>
      {
         try
         {
           Work(cancelSource.Token); //).Start();
         }
         catch (OperationCanceledException)
         {
            Console.WriteLine("Canceled!");
         }
         }).Start();

      Thread.Sleep(1000);
      cancelSource.Cancel(); // Safely cancel worker.
      Console.ReadLine();
    }
    private static void Work(CancellationToken cancelToken)
    {
      while (true)
      {
        Console.Write("345");
        cancelToken.ThrowIfCancellationRequested();
      }
    }
  }
}

您可以按如下方式實現您的工作方法:

private static void Work(CancellationToken cancelToken)
{
    while (true)
    {
        if(cancelToken.IsCancellationRequested)
        {
            return;
        }
        Console.Write("345");
    }
}

而已。 你總是需要自己處理取消——在適當的時候退出方法退出(這樣你的工作和數據處於一致的狀態)

更新:我不喜歡寫while (!cancelToken.IsCancellationRequested)因為通常很少有退出點可以在循環體中安全地停止執行,並且循環通常有一些邏輯條件可以退出(迭代集合中的所有項目等)。 所以我認為最好不要混合這些條件,因為它們有不同的意圖。

關於避免CancellationToken.ThrowIfCancellationRequested()注意事項:

Eamon Nerbonne 有問題評論

...替換ThrowIfCancellationRequested用一堆檢查IsCancellationRequested優雅退出,正如這個答案所說。 但這不僅僅是一個實現細節; 影響可觀察行為:任務將不再以取消狀態結束,而是以RanToCompletion 這不僅會影響顯式狀態檢查,而且會更巧妙地影響任務鏈接,例如ContinueWith ,具體取決於所使用的TaskContinuationOptions 我會說避免ThrowIfCancellationRequested是危險的建議。

與前面的RulyCanceler類代碼相比,我想使用CancellationTokenSource運行代碼。

取消令牌中所述,如何使用它,即不引發/捕捉異常? 我可以使用IsCancellationRequested屬性嗎?

我試圖這樣使用它:

cancelToken.ThrowIfCancellationRequested();

try
{
  new Thread(() => Work(cancelSource.Token)).Start();
}
catch (OperationCanceledException)
{
  Console.WriteLine("Canceled!");
}

但這給了cancelToken.ThrowIfCancellationRequested();一個運行時錯誤cancelToken.ThrowIfCancellationRequested(); 在方法Work(CancellationToken cancelToken)

System.OperationCanceledException was unhandled
  Message=The operation was canceled.
  Source=mscorlib
  StackTrace:
       at System.Threading.CancellationToken.ThrowIfCancellationRequested()
       at _7CancellationTokens.Token.Work(CancellationToken cancelToken) in C:\xxx\Token.cs:line 33
       at _7CancellationTokens.Token.<>c__DisplayClass1.<Main>b__0() in C:\xxx\Token.cs:line 22
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:

我成功運行的代碼在新線程中捕獲了OperationCanceledException:

using System;
using System.Threading;
namespace _7CancellationTokens
{
  internal class Token
  {
    private static void Main()
    {
      var cancelSource = new CancellationTokenSource();
      new Thread(() =>
      {
         try
         {
           Work(cancelSource.Token); //).Start();
         }
         catch (OperationCanceledException)
         {
            Console.WriteLine("Canceled!");
         }
         }).Start();

      Thread.Sleep(1000);
      cancelSource.Cancel(); // Safely cancel worker.
      Console.ReadLine();
    }
    private static void Work(CancellationToken cancelToken)
    {
      while (true)
      {
        Console.Write("345");
        cancelToken.ThrowIfCancellationRequested();
      }
    }
  }
}

您可以使用取消令牌創建任務,當您應用轉到后台時,您可以取消此令牌。

您可以在 PCL https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/app-lifecycle 中執行此操作

var cancelToken = new CancellationTokenSource();
Task.Factory.StartNew(async () => {
    await Task.Delay(10000);
    // call web API
}, cancelToken.Token);

//this stops the Task:
cancelToken.Cancel(false);

花葯解決方案是 Xamarin.Forms 中的用戶計時器,當應用程序轉到后台時停止計時器https://xamarinhelp.com/xamarin-forms-timer/

可以使用ThrowIfCancellationRequested而不處理異常!

ThrowIfCancellationRequested的使用意味着在Task (而不是Thread )中使用。 Task ,您不必自己處理異常(並獲得未處理的異常錯誤)。 這將導致離開Task ,並且Task.IsCancelled屬性將為 True。 不需要異常處理。

在您的特定情況下,將Thread更改為Task

Task t = null;
try
{
    t = Task.Run(() => Work(cancelSource.Token), cancelSource.Token);
}

if (t.IsCancelled)
{
    Console.WriteLine("Canceled!");
}

您必須將CancellationToken傳遞給 Task,它會定期監視令牌以查看是否請求取消。

// CancellationTokenSource provides the token and have authority to cancel the token
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;  

// Task need to be cancelled with CancellationToken 
Task task = Task.Run(async () => {     
  while(!token.IsCancellationRequested) {
      Console.Write("*");         
      await Task.Delay(1000);
  }
}, token);

Console.WriteLine("Press enter to stop the task"); 
Console.ReadLine(); 
cancellationTokenSource.Cancel(); 

在這種情況下,操作將在請求取消時結束, Task將具有RanToCompletion狀態。 如果您想確認您的任務已被取消,您必須使用ThrowIfCancellationRequested拋出OperationCanceledException異常。

Task task = Task.Run(async () =>             
{                 
    while (!token.IsCancellationRequested) {
         Console.Write("*");                      
         await Task.Delay(1000);                
    }           
    token.ThrowIfCancellationRequested();               
}, token)
.ContinueWith(t =>
 {
      t.Exception?.Handle(e => true);
      Console.WriteLine("You have canceled the task");
 },TaskContinuationOptions.OnlyOnCanceled);  
 
Console.WriteLine("Press enter to stop the task");                 
Console.ReadLine();                 
cancellationTokenSource.Cancel();                 
task.Wait(); 

希望這有助於更好地理解。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM