2017-09-19 2 views
-1

매 x 분마다 스크린 샷 태스크를 실행하려고하지만 주어진 취소 토큰을 사용하여 태스크를 취소하려는 경우 그렇지 않습니다. 아무것도하는 것처럼 보입니다. 여기 다른 메소드에서 호출 된 취소 토큰을 사용하여 태스크를 주기적으로 실행

내 시작 방법 코드 :

var CancellationTokenSource = new CancellationTokenSource(); 

     CancellationTokenSource?.Cancel(); 

     CancellationTokenSource = new CancellationTokenSource(); 

     var token = CancellationTokenSource.Token; 
     await RunPeriodically(async() => 
     { 

      var screenCaptured = TakeScreenshot(); 

      if (screenCaptured == null || CancellationTokenSource.Token.IsCancellationRequested) 
       return; 

      var correctUserName = Settings.Default.Username.Split('.'); 
      var parsedUsername = correctUserName[0] + " " + correctUserName[1]; 
      await ScreenshotHelper.UploadScreenshotAsync(ProjectName, "screenshotscontainer", 
       screenCaptured.ToArray(), Environment.MachineName, parsedUsername); 
      Console.WriteLine("Took Screenshot: " + DateTime.Now.ToString(CultureInfo.InvariantCulture)); 

     }, TimeSpan.FromSeconds(3), token); 

여기에 실행을 주기적 코드 : 나는이 실행됩니다 클래스의 간단한 예를 노크 거라고 생각

public async Task RunPeriodically(Action action, TimeSpan interval, CancellationToken token) 
    { 
     while (true) 
     { 
      action(); 
      await Task.Delay(interval, token); 
     } 
    } 
+3

'RunPeriodically' 메소드에서'await'없이'async''Action'을 호출합니다. 그리고 '비동기 무효화'는 일반적으로 나쁜 결정입니다. 다시 디자인하십시오. – dymanoid

+0

왜 취소되지 않는지 알 수는 없지만 다른 문제가 있습니다. 업로드를 '대기'할 때'action()'호출이 _ 반환됩니다. 그래서 아마도 당신이 생각하는 것보다 더 자주 전화했을 것입니다. 그리고'while (true)'는'CancellationToken'을 처리하지 않습니다 (그러나'Task.Delay'는'TaskCancelledException' afaik를 던져야합니다). –

+2

실제로 어떤 시점에서 작업을 취소 하시겠습니까? 당신은 새로운'CancellationTokenSource'를 생성하고 그 사실 후에 결코 그것을 취소하지 않습니다. – Nkosi

답변

0

프로세스를 종료하고 일정 기간 대기 한 다음 스레드를 차단하지 않고 프로세스를 다시 시작하십시오.

class RepeatableProcess 
{ 
    private Timer processTimer; 
    private int delay; 
    private CancellationTokenSource source; 
    private CancellationToken token; 
    private Action processToRun; 
    private bool canStart = true; 


    public RepeatableProcess(int delaySeconds,Action process) 
    { 
     delay = delaySeconds; 
     processToRun = process; 
    } 

    public void Start() 
    { 
     if (canStart) 
     { 
      canStart = false; 
      source = new CancellationTokenSource(); 
      token = source.Token; 
      processTimer = new Timer(TimedProcess, token, Timeout.Infinite, Timeout.Infinite); 
      processTimer.Change(0, Timeout.Infinite); 
     } 

    } 

    public void Stop() 
    { 
     source.Cancel(); 
    } 

    public void TimedProcess(object state) 
    { 

     CancellationToken ct = (CancellationToken)state; 
     if (ct.IsCancellationRequested) 
     { 
      Console.WriteLine("Timer Stopped"); 
      processTimer.Dispose(); 
      canStart = true; 
     } 
     else 
     { 
      processToRun.Invoke(); 
      processTimer.Change(delay, Timeout.Infinite); 
     } 
    } 

} 

Start 메서드는 절대 시작하지 않고 반복하지 않는 타이머를 만듭니다. 그런 다음 프로세스가 즉시 시작되어 한 번만 실행됩니다.

TimedProcess 메서드는 취소를 확인하고 지정된 프로세스를 실행합니다. 프로세스가 완료된 후 타이머는 지정된 지연 후 시작되고 한 번만 실행되도록 설정됩니다.

타이머가 작동하면 스레드 풀에서 스레드를 가져옵니다. 프로세스가 완료 될 때까지 타이머가 다시 실행되도록 설정되어 있지 않기 때문에 오버런 문제가 발생할 수 없습니다.

이 클래스는 더 많은 보호가 필요하지만 이는 단지 예일뿐입니다. 희망이 도움이됩니다.