태그 보관물: timer

timer

C # 타이머가 별도의 스레드에서 경과합니까? 있다고 가정 해 보겠습니다.

System.Timers.Timer가 그것을 생성 한 스레드가 아닌 별도의 스레드에서 경과합니까?

5 초마다 실행되는 타이머가있는 수업이 있다고 가정 해 보겠습니다. 타이머가 실행되면 elapsed 메서드에서 일부 개체가 수정됩니다. 이 개체를 수정하는 데 10 초처럼 오랜 시간이 걸린다고 가정 해 보겠습니다. 이 시나리오에서 스레드 충돌이 발생할 수 있습니까?



답변

대한 System.Timers.Timer :

아래 Brian Gideon의 답변을 참조하십시오.

대한 이 System.Threading.Timer :

타이머에 대한 MSDN 설명서는 다음과 같이 설명합니다.

System.Threading.Timer 클래스 는 ThreadPool 스레드에서 콜백을 만들고 이벤트 모델을 전혀 사용하지 않습니다.

따라서 실제로 타이머는 다른 스레드에서 경과합니다.


답변

때에 따라 다르지. 는 System.Timers.Timer두 가지 작동 모드가 있습니다.

SynchronizingObjectISynchronizeInvoke인스턴스로 설정된 경우 Elapsed동기화 개체를 호스팅하는 스레드 에서 이벤트가 실행됩니다. 보통 이러한 ISynchronizeInvoke경우는 보통 오래된 이외의 아무것도 없습니다 Control그리고 Form우리는 모든 잘 알고있는 것으로 인스턴스. 따라서이 경우 Elapsed이벤트는 UI 스레드에서 호출되며 System.Windows.Forms.Timer. 그렇지 않으면 실제로 ISynchronizeInvoke사용 된 특정 인스턴스 에 따라 다릅니다 .

경우 SynchronizingObjectIS 그때는 null Elapsed이벤트가 불려 ThreadPool스레드 그리고 그것은 유사 동작 System.Threading.Timer. 사실, 실제로는 System.Threading.Timer이면에서를 사용하고 필요한 경우 타이머 콜백을받은 마샬링 작업을 수행 합니다.


답변

각 elapsed 이벤트는 이전 Elapsed가 아직 실행되지 않는 한 동일한 스레드에서 발생합니다.

그래서 그것은 당신을 위해 충돌을 처리합니다

이것을 콘솔에 넣어보십시오

static void Main(string[] args)
{
    Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
    var timer = new Timer(1000);
    timer.Elapsed += timer_Elapsed;
    timer.Start();
    Console.ReadLine();
}

static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    Thread.Sleep(2000);
    Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
}

당신은 이와 같은 것을 얻을 것입니다

10
6
12
6
12

여기서 10은 호출 스레드이고 6과 12는 bg elapsed 이벤트에서 발생합니다. Thread.Sleep (2000)을 제거하면; 당신은 이와 같은 것을 얻을 것입니다

10
6
6
6
6

충돌이 없기 때문에.

그러나 이것은 여전히 ​​당신에게 문제를 남깁니다. 5 초마다 이벤트를 실행하고 편집하는 데 10 초가 걸리는 경우 일부 편집을 건너 뛰려면 잠금이 필요합니다.


답변

System.Timers.Timer의 경우 SynchronizingObject가 설정되지 않은 경우 별도의 스레드에 있습니다.

    static System.Timers.Timer DummyTimer = null;

    static void Main(string[] args)
    {
        try
        {

            Console.WriteLine("Main Thread Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId);

            DummyTimer = new System.Timers.Timer(1000 * 5); // 5 sec interval
            DummyTimer.Enabled = true;
            DummyTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnDummyTimerFired);
            DummyTimer.AutoReset = true;

            DummyTimer.Start();

            Console.WriteLine("Hit any key to exit");
            Console.ReadLine();
        }
        catch (Exception Ex)
        {
            Console.WriteLine(Ex.Message);
        }

        return;
    }

    static void OnDummyTimerFired(object Sender, System.Timers.ElapsedEventArgs e)
    {
        Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId);
        return;
    }

DummyTimer가 5 초 간격으로 실행되었는지 확인하는 출력 :

Main Thread Id: 9
   12
   12
   12
   12
   12
   ... 

따라서, OnDummyTimerFired는 Workers 스레드에서 실행됩니다.

아니요, 더 복잡합니다. 간격을 10ms로 줄이면

Main Thread Id: 9
   11
   13
   12
   22
   17
   ... 

이는 다음 틱이 실행될 때 OnDummyTimerFired의 이전 실행이 완료되지 않은 경우 .NET이이 작업을 수행하기 위해 새 스레드를 생성하기 때문입니다.

더 복잡하게하는 것은 “System.Timers.Timer 클래스는이 딜레마를 쉽게 처리 할 수있는 방법을 제공합니다. 공용 SynchronizingObject 속성을 노출합니다.이 속성을 Windows Form의 인스턴스 (또는 Windows Form의 컨트롤)로 설정하면 Elapsed 이벤트 처리기의 코드는 SynchronizingObject가 인스턴스화 된 동일한 스레드에서 실행됩니다. “

http://msdn.microsoft.com/en-us/magazine/cc164015.aspx#S2


답변

elapsed 이벤트가 간격보다 오래 걸리면 elapsed 이벤트를 발생시키는 또 다른 스레드를 생성합니다. 그러나 이에 대한 해결 방법이 있습니다.

static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
   try
   {
      timer.Stop();
      Thread.Sleep(2000);
      Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
   }
   finally
   {
     timer.Start();
   }
}


답변