2016-08-01 4 views
0

을 Task.Run를 사용하고 대기합니다 :올바른 방법은 내가 타이머에 의해 실행되는 코드의 다음 블록이

private void CheckForScheduleItemsTimerOnElapsed(Object sender, ElapsedEventArgs elapsedEventArgs) 
{ 
    if (CurrentlyProcessingMsgs) 
     return; 

    CurrentlyProcessingMsgs = true; 

    var task = Task.Run(() => { 
      CheckForScheduleItems.Process(_cancellationToken); 
     }, _cancellationToken); 

    task.Wait(_cancellationToken); 

    CurrentlyProcessingMsgs = false; 
} 

지금은 데 문제가를 그 어떤 경우에는, 라인

CurrentlyProcessingMsgs = false; 

이 호출되지 않습니다. Task.Wait가 작업이 완료 될 때까지 기다렸다가 계속 진행하여 그 플래그를 다시 설정해야한다는 것이 내 이해입니다. 그러나 어떤 경우에는 그런 일이 일어나지 않습니다. (참고 :이 타이머는 서비스에 의해 관리되고 있습니다.) 어떤 상황이 발생했는지는 시스템 종료시에 CurrentlyProcessingMsgs의 값을 확인하는 중이고 작업이 완료된 후에도 여전히 유효합니다.

위의 목표는 위에 표시된 것처럼 여러 타이머를 사용 중지하는 것입니다. 각 타이머는 위에 표시된 것과 비슷한 처리를 수행하며 각 프로세스를 별도의 스레드에서 실행하려고합니다. CancellationToken에 대한 이해가 잘못되었습니다.이 경우 타이머와 작업을 설정하여 이러한 메서드를 실행하고 각각을 별도의 스레드에 배치하는 올바른 방법은 무엇입니까?

+0

타이머에 대한 질문은 사용중인 타이머에 따라 다릅니다. .NET에 내장 된 일부 타이머는 자동으로 스레드 풀을 사용하여 타이머를 시작합니다 (Task.Run이 수행하는 것과 동일한 작업). 사용중인 타이머 클래스를 표시해야합니다. 당신은 이미하고 싶은 일을하고 있을지도 모릅니다. –

+0

System.Timers.Timer 클래스를 사용하여 타이머를 시작합니다. –

+0

['Timer.SynchronizingObject'] (https://msdn.microsoft.com/en-us/library/system.timers.timer.synchronizingobject (v = vs.110) .aspx) 값이 설정되어 있습니까? 'null'인 경우 타이머가 이미 타이머 틱을 실행하는 새 스레드를 만들고 있으므로 추가 작업을 수행 할 필요가 없습니다. –

답변

1

_cancellationToken이 취소되면 예외가 발생합니다. 당신은 취소 또는 다른 예외가 Process이/마침내

private void CheckForScheduleItemsTimerOnElapsed(Object sender, ElapsedEventArgs elapsedEventArgs) 
{ 
    if (CurrentlyProcessingMsgs) 
     return; 

    CurrentlyProcessingMsgs = true; 
    try 
    { 
     var task = Task.Run(() => { 
       CheckForScheduleItems.Process(_cancellationToken); 
      }, _cancellationToken); 

     task.Wait(_cancellationToken); 
    } 
    finally 
    { 
     CurrentlyProcessingMsgs = false; 
    } 
} 

P.S.을 차단 시도에 CurrentlyProcessingMsgs = false;을 넣어 의해 제기되는 경우에도 플래그가 변경되어 있는지 확인하려면 Task.Run을 수행 할 좋은 이유가 거의 없습니다. 매우 유사한 로직을 가져야하는 다음을 수행하는 것은 오버 헤드가 훨씬 적습니다. 여기

private void CheckForScheduleItemsTimerOnElapsed(Object sender, ElapsedEventArgs elapsedEventArgs) 
{ 
    if (CurrentlyProcessingMsgs) 
     return; 

    CurrentlyProcessingMsgs = true; 
    try 
    { 
     _cancellationToken.ThrowIfCancellationRequested(); 
     CheckForScheduleItems.Process(_cancellationToken); 
    } 
    finally 
    { 
     CurrentlyProcessingMsgs = false; 
    } 
} 

는 예외를 캐치와 함께 업데이트 된 버전이다.

private void CheckForScheduleItemsTimerOnElapsed(Object sender, ElapsedEventArgs elapsedEventArgs) 
{ 
    if (CurrentlyProcessingMsgs) 
     return; 

    CurrentlyProcessingMsgs = true; 
    try 
    { 
     _cancellationToken.ThrowIfCancellationRequested(); 
     CheckForScheduleItems.Process(_cancellationToken); 
    } 
    catch (OperationCanceledException ex) 
    { 
     //If the task was canceled for some other reason than our token raise the exception. 
     if(ex.CancellationToken != _cancellationToken) 
      throw; 
    } 
    finally 
    { 
     CurrentlyProcessingMsgs = false; 
    } 
} 
+0

다른 스레드 중 하나에서 시작한 다음 즉시 현재 스레드를 차단합니다. 당신은 여분의 동시 작업이 여기에, 당신이하고있는 여분의 전화 스택 여분의 RAM을 사용하고 있습니다. 또한'Wait'이 토큰에'OperationCanceledException'을 전달하려고 할 때, 정상적으로 멈추고 싶다면 예외를 잡아야합니다. –

+0

질문이 업데이트되었습니다. TPL을 올바르게 사용하는 방법에 대한 정보를 분명히 오해하고 있습니다. –

관련 문제