2016-10-11 3 views
2

이것이 취소 작업의 첫 번째 스레드가 아니라는 것을 알았지 만 지금까지는 내 필요에 맞는 적절한 항목을 찾지 못했습니다. 나는 모듈이 동적으로 구성을 기반으로, 컨트롤러 클래스가 초기화되는 모듈 식 시스템을 가지고C# UWP 취소 작업 + 시그널링 자식

  • :

    여기 경우입니다.

  • 각 모듈은 Connect() 메소드를 구현합니다. 방법 자체는 블랙 박스이지만 배경 정보는 일부 모듈이 블루투스 연결을 생성하려고 시도하는 것입니다.
  • 연결에 너무 오래 걸리면 시도를 취소하고 5 분 후에 다시 시도하고 싶습니다.

처음에는 재시도 논리를 모듈 구현에 넣었습니다. 그건 잘 작동하지만, 모듈을 통해 반복되고 실제로 모듈의 핵심 책임에 속하지 않습니다. 그래서 저는 컨트롤러에 로직을 넣는 것을 고려 했습니다만, 좋은 구현을 찾기 위해 고심하고 있습니다.

여기서 문제는 내가 작업을 취소하고 싶을뿐만 아니라 좋은 방식으로 작업하기를 원한다는 것입니다. 닫기/처분 할 객체가있는 경우 모듈은 그렇게 할 수 있어야합니다. 또한 모듈은 "연결 중"대신 "연결 끊김"으로 상태를 설정할 수 있어야합니다 (그리고 공개적 방법보다 외부에서 상태를 변경하는 모듈을 사용하게하십시오). 연결 및 시간 초과 논리가 모듈 내부에있을 때 이것은 모두 쉬운 일 이었지만 외부 타임 아웃을 도입하는 것이 더 어려워졌습니다. 여기

는 모듈이 시간에 응답하지 않을 때 내가 예상 흐름입니다 :

  • 컨트롤러는 새 모듈 인스턴스를 생성
  • 컨트롤러는
  • 컨트롤러는 또한 초기화 모듈을 연결하기 위해 연결()를 호출 모듈을 모니터링하는 타이머가 30 초 내에 연결을 완료합니다.
  • 타이머가 작동하지 않고 모듈이 아직 작업을 완료하지 않았습니다.
  • 연결() 메소드에 취소가 통지되어야합니다. 바람직하게는 잡히고 처리 할 수있는 Connect 메소드 내부에 예외를 던지십시오.
  • 예외 처리기는 일을 깔끔하게 정리할 수 있으며 메서드가 반환됩니다.

위의 흐름은 내가 발견 한만큼 존재하지 않습니다. 취소 토큰은 다르게 작동하며 이벤트 나 폴링을 필요로합니다. 좋은 생각이지만,이 논리를 제 모듈에 포함시키는 것으로 돌아가서 전체 재시도 작업을 시작하지 않는 것이 어떻습니까? 그래서 저에게 이것을 허용하는 달콤한 패턴이 있는지 궁금합니다.

저는 Windows 10 UWP 용으로 구축하고 있습니다. 나는 그 순간에 내가 가진 것이 어쨌든 허튼이기 때문에 어떤 코드도 의도적으로 포함하지 않았다.

답변

1

CancellationToken의 비동기 작업에서 취소를 지원하지 않거나 스레드 또는 프로세스를 종료하지 않는 한 실행중인 코드를 중지 할 수있는 방법이 없습니다. 다음은 시간 종료의 샘플입니다.

public static async Task Run() 
      { 
       var module = new Module(); 

       //No timeout 
       await module.Connect(1, CancelAfter(2000)); 

       try 
       { 
        // Timeout 
        await module.Connect(5, CancelAfter(1000)); 
       } 
       catch (Exception) 
       { 

        module.Dispose(); 
       } 

      } 

      public static CancellationToken CancelAfter(int millisecondsDelay) 
      { 
       var token = new CancellationTokenSource(); 
       token.CancelAfter(millisecondsDelay); 
       return token.Token; 
      } 

      public class Module : IDisposable 
      { 
       public async Task Connect(int count, CancellationToken cancel) 
       { 
        for (int i = 0; i < count; i++) 
        { 
         //This is just to simulte some work Task.Delay can be canceled as well with Task.Delay(500,cancel) 
         await Task.Delay(500); 
         cancel.ThrowIfCancellationRequested(); 
        } 
       } 

       public void Dispose() 
       { 

       } 
      } 

당신은

public static class TaskTimeout 
    { 
     public static async Task TimeoutAfter(this Task task, int millisecondsTimeout) 
     { 
      if (task != await Task.WhenAny(task, Task.Delay(millisecondsTimeout))) 
      { throw new TimeoutException(); } 
     } 

     public static async Task<T> TimeoutAfter<T>(this Task<T> task, int millisecondsTimeout) 
     { 
      if (task != await Task.WhenAny(task, Task.Delay(millisecondsTimeout))) 
      { throw new TimeoutException(); } 
      else { return task.Result; } 
     } 
    } 

으로 모든 작업을 제한 시간을 초과 할 수 있습니다 그러나 연결이 취소 할 수있는 취소 할 경우에만이 당신에게 연결을 취소하지 않습니다. .net에서 대부분의 비동기 호출은 CancellationToken을 구현 했으므로 연결에 사용하면됩니다.

+0

정확히 그게 문제입니다. My Connect()에는 토큰을 계속해서 반복적으로 확인할 수있는 for 또는 while 루프가 없습니다. 그것은 연결 호출을 시작하고 연결이 될 때까지 기다립니다. 어떻게 든 죽일 필요가있는 호출입니다. 타이머 이벤트에서 객체를 삭제하여 현재 수행하고 있습니다. 특정 시점에서 Connect() 메소드 내에서 런타임 예외를 트리거 할 수 있다면 훨씬 더 좋을 것입니다. – Jasper

+0

모든 작업을 시간 초과 할 수있는 방법에 대한 편집을했지만 처리를 처리해야합니다. –