[c#] CancellationToken 속성을 사용하는 방법은 무엇입니까?

RulyCanceler 클래스 에 대한 이전 코드와 비교 하여 CancellationTokenSource.

취소 토큰 에서 언급 한대로 예외를 던지거나 잡지 않고 어떻게 사용합니까? IsCancellationRequested부동산을 사용할 수 있습니까 ?

나는 이것을 다음과 같이 사용하려고 시도했다.

cancelToken.ThrowIfCancellationRequested();

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

그러나 이것은 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():

문제의 코멘트 에 의해 에이 몬 Nerbonne :

… 이 답변이 말했듯이 출구에 ThrowIfCancellationRequested대한 IsCancellationRequested일련 의 검사로 정상적으로 대체 됩니다. 그러나 이것은 단순한 구현 세부 사항이 아닙니다. 관찰 가능한 동작에 영향을줍니다 : 작업은 더 이상 취소 된 상태로 끝나지 않고 RanToCompletion. 그리고 그것은 명시적인 상태 검사뿐만 아니라 더 미묘하게 ContinueWithTaskContinuationOptions사용되는 것에 따라 예를 들어 작업 체인에 영향을 줄 수 있습니다 . 피하는 ThrowIfCancellationRequested것은 위험한 조언 이라고 말하고 싶습니다 .


답변

안녕하세요.

stackoverflow에 게시 된 모든 것을 맹목적으로 신뢰해서는 안됩니다. Jens 코드의 주석이 올바르지 않습니다. 매개 변수는 예외 발생 여부를 제어하지 않습니다.

MSDN은 그 매개 변수가 무엇을 제어하는지 매우 명확합니다. 읽어 보셨습니까?
http://msdn.microsoft.com/en-us/library/dd321703(v=vs.110).aspx

경우 throwOnFirstException에 해당하는 예외 즉시 처리되지 나머지 콜백 및 캔슬 조작을 방지하는 취소 호출 밖으로 전달한다. 경우
throwOnFirstException거짓,이 오버로드는 던져 예외를 집계한다AggregateException 예외를 던지는 하나의 콜백이 실행되는 다른 등록 된 콜백을 방지하지 않도록.

CancellationTokenSource토큰 자체가 아닌 Cancel이 호출되고 소스가 관리하는 각 토큰의 상태를 변경 하기 때문에 변수 이름도 잘못되었습니다 .


답변

취소 토큰으로 Task를 생성 할 수 있으며, 백그라운드로 이동할 때이 토큰을 취소 할 수 있습니다.

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);

Anther 솔루션은 Xamarin.Forms의 사용자 타이머, 앱이 백그라운드로 이동할 때 타이머 중지
https://xamarinhelp.com/xamarin-forms-timer/


답변

예외를 처리하지 않고 사용할 수 있습니다ThrowIfCancellationRequested !

의 사용은 (가 아님 ) ThrowIfCancellationRequested내에서 사용됩니다 . 에서 사용 하면 예외를 직접 처리 할 필요가 없습니다 (그리고 처리되지 않은 예외 오류가 발생 함). 을 떠나게 되고 속성은 True가됩니다. 예외 처리가 필요하지 않습니다.TaskThreadTaskTaskTask.IsCancelled

특정 경우에는 ThreadTask.

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

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


답변

CancellationToken취소 요청 여부를 확인하기 위해 주기적으로 토큰을 모니터링하는 태스크에을 전달해야합니다 .

CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;
Task task = Task.Run(() => {     
  while(!token.IsCancellationRequested) {
      Console.Write("*");         
      Thread.Sleep(1000);
  }
}, token);
Console.WriteLine("Press enter to stop the task");
Console.ReadLine();
cancellationTokenSource.Cancel(); 

이 경우 취소가 요청되면 작업이 종료 Task되고 RanToCompletion상태가됩니다. 당신이 인정을 받으려면 귀하의 작업이 취소되었습니다 , 당신은 사용할 필요가 ThrowIfCancellationRequested던져 OperationCanceledException예외.

Task task = Task.Run(() =>             
{                 
    while (!token.IsCancellationRequested) {
         Console.Write("*");                      
        Thread.Sleep(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(); 

이것이 더 잘 이해하는 데 도움이되기를 바랍니다.


답변