[c#] C #의 System.Threading.Timer가 작동하지 않는 것 같습니다. 3 초마다 매우 빠르게 실행됩니다.

타이머 개체가 있습니다. 매분 실행되기를 바랍니다. 특히, OnCallBack메서드를 실행해야 하며 OnCallBack메서드가 실행되는 동안 비활성화됩니다 . OnCallBack메서드가 완료 되면 (a OnCallBack) 타이머를 다시 시작합니다.

지금 내가 가지고있는 것은 다음과 같습니다.

private static Timer timer;

private static void Main()
{
    timer = new Timer(_ => OnCallBack(), null, 0, 1000 * 10); //every 10 seconds
    Console.ReadLine();
}

private static void OnCallBack()
{
    timer.Change(Timeout.Infinite, Timeout.Infinite); //stops the timer
    Thread.Sleep(3000); //doing some long operation
    timer.Change(0, 1000 * 10);  //restarts the timer
}

그러나 작동하지 않는 것 같습니다. 3 초마다 매우 빠르게 실행됩니다. 기간을 올리더라도 (1000 * 10). 눈이 멀어 보이는 것 같습니다.1000 * 10

내가 뭘 잘못 했어?



답변

이것은 System.Threading.Timer의 올바른 사용법이 아닙니다. Timer를 인스턴스화 할 때 거의 항상 다음을 수행해야합니다.

_timer = new Timer( Callback, null, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite );

이렇게하면 간격이 경과했을 때 타이머가 한 번만 틱하도록 지시합니다. 그런 다음 콜백 기능에서 작업이 완료되면 타이머를 변경하십시오. 예:

private void Callback( Object state )
{
    // Long running operation
   _timer.Change( TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite );
}

따라서 동시성이 없기 때문에 잠금 메커니즘이 필요하지 않습니다. 타이머는 다음 간격과 장기 실행 작업 시간이 경과 한 후 다음 콜백을 시작합니다.

타이머를 정확히 N 밀리 초로 실행해야하는 경우 스톱워치를 사용하여 장기 실행 작업 시간을 측정 한 다음 적절하게 Change 메서드를 호출하는 것이 좋습니다.

private void Callback( Object state )
{
   Stopwatch watch = new Stopwatch();

   watch.Start();
   // Long running operation

   _timer.Change( Math.Max( 0, TIME_INTERVAL_IN_MILLISECONDS - watch.ElapsedMilliseconds ), Timeout.Infinite );
}

나는 강력하게 – 사람이 .NET을 수행하고, 제프리 리히터의 책을 읽을 수있다 CLR 사용하고 격려 C #을 통해 CLR을 가능한 한 빨리를 읽기. 타이머와 스레드 풀은 여기에 매우 자세히 설명되어 있습니다.


답변

타이머를 중지 할 필요는 없습니다 . 이 게시물에서 좋은 솔루션을 참조하십시오 .

“타이머가 콜백 메서드를 계속 실행하도록 할 수 있지만 Monitor.TryEnter / Exit에 재진입이 아닌 코드를 래핑 할 수 있습니다.이 경우 타이머를 중지 / 다시 시작할 필요가 없습니다. 중복 호출은 잠금을 획득하지 않고 즉시 반환됩니다.”

private void CreatorLoop(object state) 
 {
   if (Monitor.TryEnter(lockObject))
   {
     try
     {
       // Work here
     }
     finally
     {
       Monitor.Exit(lockObject);
     }
   }
 }


답변

사용은 System.Threading.Timer필수인가요?

그렇지 않은 경우 System.Timers.Timer편리한 Start()Stop()메서드 (및 AutoResetfalse로 설정할 수 있는 속성이 있으므로 Stop()필요하지 않고 Start()실행 후 호출 하기 만하면됩니다 ).


답변

나는 그냥 할 것입니다.

private static Timer timer;
 private static void Main()
 {
   timer = new Timer(_ => OnCallBack(), null, 1000 * 10,Timeout.Infinite); //in 10 seconds
   Console.ReadLine();
 }

  private static void OnCallBack()
  {
    timer.Dispose();
    Thread.Sleep(3000); //doing some long operation
    timer = new Timer(_ => OnCallBack(), null, 1000 * 10,Timeout.Infinite); //in 10 seconds
  }

주기를 직접 제어하려고하므로주기 매개 변수를 무시하십시오.


당신이 지정 유지하기 때문에 원래 코드는 가능한 한 빨리 실행 0에 대한 dueTime매개 변수입니다. 에서 Timer.Change:

dueTime이 영 (0)이면 콜백 메서드가 즉시 호출됩니다.


답변

 var span = TimeSpan.FromMinutes(2);
 var t = Task.Factory.StartNew(async delegate / () =>
   {
        this.SomeAsync();
        await Task.Delay(span, source.Token);
  }, source.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

source.Cancel(true/or not);

// or use ThreadPool(whit defaul options thread) like this
Task.Start(()=>{...}), source.Token)

내부에 루프 스레드를 사용하는 것을 좋아한다면 …

public async void RunForestRun(CancellationToken token)
{
  var t = await Task.Factory.StartNew(async delegate
   {
       while (true)
       {
           await Task.Delay(TimeSpan.FromSeconds(1), token)
                 .ContinueWith(task => { Console.WriteLine("End delay"); });
           this.PrintConsole(1);
        }
    }, token) // drop thread options to default values;
}

// And somewhere there
source.Cancel();
//or
token.ThrowIfCancellationRequested(); // try/ catch block requred.


답변