2014-04-13 10 views
1

아래에 정의 된대로 타이머가 있습니다. 타이머는 장기 실행 작업을 실행합니다. 내가 가진 문제는 타이머가 다시 실행되고 다른 타이머 실행이 시작될 때 (예 : _timer_Elapsed)입니다. 타이머가 끝난 후 한 간격을 실행하도록 타이머를 가져올 수 있습니까? 지금은 여러 가지 타이머 실행이 동시에 일어날 수 있고 그로 인해 모든 코드 문제가 발생합니다.다중 타이머 경과 문제

protected override void OnStart(string[] args) 
     { 

      _timer = new System.Timers.Timer(); 
      _timer.AutoReset = false; 
      _timer.Interval = (Convert.ToInt32(ConfigurationManager.AppSettings["CheckInterval"])); 
      _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed); 
      _timer.Enabled = true; 
      _timer.Start(); // Start timer 

     } 


public static void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
     { 
      try 
      { 
       _timer.Interval = (Convert.ToInt32(ConfigurationManager.AppSettings["CheckInterval"])); 

       BLLGenericResult SystemCheckItems_Result = ServiceItemOperations.CheckItems(); // Long Running Task 

      } 
      catch (Exception ex) 
      { 
       // Exception handling... 
      } 
      finally 
      { 
       _timer.Start(); 
      } 
     } 
+2

AutoReset = false를 사용하면 명시 적으로 다시 활성화하지 않으면 타이머가 다시 작동하지 않습니다. Elapsed 이벤트 핸들러가 끝나는 대신 Elapsed 이벤트 핸들러를 다시 활성화하는 것과 같이 잘못된 방법으로 잘 수행 할 수 있습니다. 또는 OnStop() 메서드를 제대로 구현하지 않습니다. –

+0

@HansPassant 예 - 나는 또한 그걸 읽었습니다. _Timer_Elapsed 메서드를 구현하고 생각하는 것을 보도록하겠습니다. – user1438082

+1

... 또는 OnStart 함수를 다시 호출하고 이전 타이머를 실행하는 새 타이머가 시작되었습니다 . –

답변

2

올바르게 써 두자. 그것은 당신을 곤경에 빠지게하는 간격 임무입니다. 문제를 보여주는 샘플 프로그램 :

using System; 

class Program { 
    static System.Timers.Timer timer; 
    static void Main(string[] args) { 
     timer = new System.Timers.Timer(); 
     timer.AutoReset = false; 
     timer.Interval = 1000; 
     timer.Elapsed += timer_Elapsed; 
     timer.Start(); 
     Console.ReadLine(); 
    } 

    static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { 
     timer.Interval = 1000; 
     Console.WriteLine("Tick"); 
    } 
} 

출력 :

Tick 
Tick 
Tick 
... 

차이를 확인하기 위해 경과 이벤트 처리기에서 간격 지정을 제거합니다.

즉, AutoReset 속성이 이면이더라도 Timer를 다시 시작하기 위해서는 Interval 속성을 할당하기 만하면됩니다. 큰 놀라움은 물론, 아무도 그걸 보지 못한다. Interval 속성을 일찍 지정하면 앞에 무거운 짐을 시작하기 전에 프로그램에서 혼란을 겪습니다. Elapsed 이벤트는 다른 스레드에서 다시 발생하지만 이전 이벤트는 아직 실행되지 않았습니다. 인터럽트 값이 너무 작 으면 스레딩 버그가 발생하기를 기다리고 있습니다. 나중에 할당해야 할 것이므로 블록 내에서 마지막으로 블록 내부에 지정해야합니다. Interval을 너무 작게 만들었고 나중에 진단하기가 어려웠습니다.

이 C# 버그입니까?

C# 언어는 별개이며 .NET Framework 버그입니다. System.Timers.Timer는 일반적으로 아주 좋은 등급이 아니며, 안전 스위치가없는 전기 톱의 유용성을 가지고 있습니다. System.Threading.Timer 클래스를 더욱 유용하게 만드는 것을 의미했습니다. 특히 가비지 수집의 습관이 너무 빨리 사라지는 문제를 해결했습니다. 한 가지 문제가 해결되었지만 세 가지 새로운 문제가 추가되었습니다. 이것은 .NET 1.0, 훈련 바퀴가있는 프레임 워크 버전으로 돌아갑니다. 그들은 더 이상 그것을 고칠 수 없으며, 너무 많은 기존 코드가 깨질 것입니다. System.Threading.Timer를 사용하면 실제로 더 효율적입니다. 변수에 참조 된 객체를 유지하십시오. 너처럼 이미.

+0

당신이 여기에 간 세부 사항은 인상적입니다 - 정말 고마워요. – user1438082

0

2017 업데이트 :

이러한 종류의 문제에 도움이 될 수있는 새로운 도구가 있습니다.

await Task.Delay(TimeSpan.FromSeconds(x));