Language/C#

[.NET] System.Threading.Timer Class에 대해

범데이 2023. 7. 20. 18:31

해당 포스팅은 Timer Class의 공식문서를 직접 번역하면서, 부연설명을 추가하여 작성한 포스팅이다.

 

 

정의

Namespace: System.Threading

Assembly: System.Runtime.dll

 

지정된 간격으로 thread pool thread에서 메서드를 실행하기 위한 메커니즘을 제공한다.이 클래스는 상속할 수 없다.

*(스레드 풀이란? 이전 포스팅 참고)

 

public sealed class Timer : MarshalByRefObject, IAsyncDisposable, IDisposable

Inheritance Object → MarsharByRefObject → Timer

Implements IDisposable, IAsyncDisposable

 

 

 

 

예제

다음 예제에서는 시그니처가 TimerCallback delegate와 동일한 CheckStatus 메서드를 포함하는 StatusChecker클래스를 정의한다. CheckStatus 메서드의 state 인수는 응용 프로그램 thread와 콜백 delegate를 실행하는 thread pool thread를 동기화하는 데 사용되는 AuthResetEvent 개체이다.

 

StatusChecker 클래스에는 두 가지 state변수도 포함된다:

invokeCount

- 콜백 메서드가 호출된 횟수를 나타낸다.

maxCount

- 콜백 메서드를 호출할 수 있는 최대 횟수를 결정한다.

 

 

 응용 프로그램 thread는 1초를 기다린 다음 250 밀리초마다 CheckStatus 콜백 메서드를 실행하는 타이머를 만든다. 그런 다음 응용 프로그램 thread는 AutoResetEvent 객체가 신호를 받을 때까지 차단된다. CheckStatus 콜백 메서드가 maxCount번 실행되면 AutoResetEvent.Set 메서드를 호출하여 AutoResetEvent 객체의 상태를 신호됨으로 설정한다.

 이렇게 처음 발생되면, 응용 프로그램 스레드는 이제 콜백 메서드가 0.5초마다 실행되도록 Change(Int32, Int32)메서드를 호출한다. AutoRestEvent 개체가 신호를 받을 때까지 다시 한 번 차단된다. 이 경우 Dispose메서드를 호출하여 타이머가 소멸되고 응용 프로그램이 종료된다.

using System;
using System.Threading;

class TimerExample
{
    static void Main()
    {
        // 타이머 콜백의 제한 시간 임계값에 도달했음을 알리는
        // AutoResetEvent를 만든다.
        var autoEvent = new AutoResetEvent(false);
        
        var statusChecker = new StatusChecker(10);

        // 1초 후에 CheckStatus를 호출하고 그 이후에는
        // 250 밀리초마다 호출하는 타이머를 만든다.
        Console.WriteLine("{0:h:mm:ss.fff} Creating timer.\\n", 
                          DateTime.Now);
        var stateTimer = new Timer(statusChecker.CheckStatus, 
                                   autoEvent, 1000, 250);

        // autoEvent가 신호를 보내면, 주기를 0.5초로 변경한다.
        autoEvent.WaitOne();
        stateTimer.Change(0, 500);
        Console.WriteLine("\\nChanging period to .5 seconds.\\n");

        // autoEvent가 두 번째 신호를 보내면, 타이머를 폐기한다.
        autoEvent.WaitOne();
        stateTimer.Dispose();
        Console.WriteLine("\\nDestroying timer.");
    }
}

class StatusChecker
{
    private int invokeCount;
    private int  maxCount;

    public StatusChecker(int count)
    {
        invokeCount  = 0;
        maxCount = count;
    }

    // 이 메서드는 타이머 delegate에 의해 호출된다.
    public void CheckStatus(Object stateInfo)
    {
        AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
        Console.WriteLine("{0} Checking status {1,2}.", 
            DateTime.Now.ToString("h:mm:ss.fff"), 
            (++invokeCount).ToString());

        if(invokeCount == maxCount)
        {
            // 카운터를 재설정하고 대기 중인 thread에 신호를 보낸다.
            invokeCount = 0;
            autoEvent.Set();
        }
    }
}

// 이 예제는 다음과 같은 출력을 표시한다:
//       11:59:54.202 Creating timer.
//       
//       11:59:55.217 Checking status  1.
//       11:59:55.466 Checking status  2.
//       11:59:55.716 Checking status  3.
//       11:59:55.968 Checking status  4.
//       11:59:56.218 Checking status  5.
//       11:59:56.470 Checking status  6.
//       11:59:56.722 Checking status  7.
//       11:59:56.972 Checking status  8.
//       11:59:57.223 Checking status  9.
//       11:59:57.473 Checking status 10.
//       
//       Changing period to .5 seconds.
//       
//       11:59:57.474 Checking status  1.
//       11:59:57.976 Checking status  2.
//       11:59:58.476 Checking status  3.
//       11:59:58.977 Checking status  4.
//       11:59:59.477 Checking status  5.
//       11:59:59.977 Checking status  6.
//       12:00:00.478 Checking status  7.
//       12:00:00.980 Checking status  8.
//       12:00:01.481 Checking status  9.
//       12:00:01.981 Checking status 10.
//       
//       Destroying timer.

 

 

비고

TimerCallback delegate를 사용하여 타이머가 실행할 메서드를 지정하자. TimerCallback delegate의 signature은 다음과 같다.

void TimerCallback(Object state)

타이머 delegate는 타이머가 구성될 때 지정되며 변경할 수 없다. 메서드는 타이머를 만든 thread에서 실행되지 않는다. 시스템에서 제공하는 ThreadPool thread에서 실행된다.

 

<팁>
.NET에는 각각 다른 기능을 제공하는 여러 타이머 클래스가 포함되어 있다.

System.Timers.Timer: 이벤트를 발생시키고 일정한 간격으로 하나 이상의 이벤트 싱크에서 코드를 실행한다. 이 클래스는 다중 thread 환경에서 서버 기반 또는 서비스 구성 요소로 사용하기 위한 것이다. 사용자 인터페이스가 없으며 런타임에 표시되지 않는다.
System.Threading.Timer: 정기적으로 thread pool thread에서 단일 콜백 메서드를 실행한다. 콜백 메서드는 타이머가 인스턴스화될 때 정의되며 변경할 수 없다. System.Timers.Timer 클래스와 마찬가지로 이 클래스는 다중 스레드 환경에서 서버 기반 또는 서비스 구성 요소로 사용하기 위한 것이다. 사용자 인터페이스가 없으며 런타임에 표시되지 않는다.
System.Windows.Forms.Timer: 이벤트를 발생시키고 일정한 간격으로 하나 이상의 이벤트 싱크에서 코드를 실행하는 Windows Form 구성 요소이다. 구성 요소에는 사용자 인터페이스가 없으며 단일 스레드 환경에서 사용하도록 설계되었다. UI스레드에서 실행된다.
System.Web.UI.Timer(.NET Framework에만 해당): 비동기 또는 동기 웹 페이지 포스트백을 정기적으로 수행하는 ASP.NET 구성 요소이다.
System.Windows.Threading.DispatcherTimer: Dispatcher 큐에 통합된 타이머이다. 이 타이머는 지정된 시간 간격으로 지정된 우선 순위로 처리된다.

 

타이머를 만들 때 메서드를 처음 실행하기 전에 대기할 시간(due time)과 후속 실행 사이에 대기할 시간(period)을 지정할 수 있다. Timer 클래스는 시스템 시계와 동일한 해상도를 가진다. 이 말은 기간이 시스템 시계의 해상도보다 작은 경우 TimerCallback delegate는 시스템 시계의 해상도로 정의된 간격(Windows 7 및 Windows 8 시스템에서 약 15밀리초)으로 실행된다. Change 메서드를 사용하여 period를 변경하거나 타이머를 비활성화할 수 있다.

 

<메모>
Timer를 사용하는 한 타이머에 대한 참조를 유지해야 한다. 모든 관리 개체와 마찬가지로 Timer에 대한 참조가 없으면 타이머도 garbage collection 대상이 된다. 타이머가 여전히 활성 상태라는 사실이 타이머 수집을 방해하지 않는
다.
<메모>
사용되는 시스템 시계는 GetTickCount에서 사용하는 것과 동일한 시계이며 timeBeginPeriod 및 timeEndPeriod로 만든 변경 사항의 영향을 받지 않는다.

 

타이머가 더 이상 필요하지 않으면 Dispose 메서드를 사용하여 타이머가 보유한 리소스를 해제한다.

콜백은 Dispose() 메서드 오버로드가 호출된 후에 발생할 수 있다. 타이머가 thread pool thread에 의한 실행을 위해 콜백을 대기열에 넣기 때문이다. Dispose(WaitHandle)메서드 오버로드를 사용하여 모든 콜백이 완료될 때까지 기다릴 수 있다.

 

타이머에 의해 실행되는 콜백 메서드는 ThreadPool thread에서 호출되기 때문에 재진입이 가능해야한다. 타이머 간격이 콜백을 실행하는 데 필요한 시간보다 짧거나 모든 thread pool thread가 사용 중이고 콜백이 여러 번 대기 중인 경우 두 thread pool thread에서 콜백을 동시에 실행할 수 있다.

 

<메모>
System.Threading.Timer 는 콜백 메서드를 사용하고 thread pool thread에서 제공하는 간단하고 가벼운 타이머이다. 콜백이 사용자 인터페이스 스레드에서 발생하지 않기 때문에 Windows Forms와 함꼐 사용하지 않는 것이 좋다. 
System.Windows.Forms.Timer 는 Windows Forms와 함께 사용하기에 더 나은 선택이다. 서버 기반 타이머 기능의 경우 이벤트를 발생시키고 추가 기능이 있는 System.Timers.Timer 사용을 고려할 수 있다.

 

 

생성자

Timer(TimerCallback)  새로 만든 Timer 개체를 상태 개체로 사용하여 무한 기간 및 무한 마감 시간으로 Timer 클래스의 새 인스턴스를 초기화한다.
Timer(TimerCallback, Object, In32, Int32) 부호 있는 32비트 정수를 사용하여 시간 간격을 지정하여 Timer 클래스의 새 인스턴스를 초기화한다.
Timer(TimerCallback, Object, Int64, Int64) 부호 있는 64비트 정수를 사용하여 Timer 클래스의 새 인스턴스를 초기화하여 시간 간격을 측정한다.
Timer(TimerCallback, Object, TimeSpan, TimeSpan) TimeSpan 값을 사용하여 시간 간격을 측정하여 Timer 클래스의 새 인스턴스를 초기화한다.
Timer(TimerCallback, Object, UInt32, UInt32) 부호 없는 32비트 정수를 사용하여 시간 간격을 측정하여 Timer 클래스의 새 인스턴스를 초기화한다.

 

 

속성

ActiveCount  현재 활성화된 타이머 수를 가져온다. 활성 타이머는 미래의 특정 시점에 틱하도록 등록되었으며 아직 취소되지 않은 것들이다.

 

 

 

주요 메서드

Change(Int32, Int32)  부호 있는 32비트 정수를 사용하여 시간 간격을 측정하여 타이머의 시작 시간과 메서드 호출 간 간격을 변경한다.
Change(Int64, Int64) 부호 있는 64비트 정수를 사용하여 시간 간격을 측정하여 타이머의 시작 시간과 메서드 호출 간 간격을 변경한다.
Change(TimeSpan, TimeSpan) TimeSpan 값을 사용하여 시간 간격을 측정하여 타이머의 시작 시간과 메서드 호출 간격을 변경한다.
Change(UInt32, UInt32) 부호 없는 32비트 정수를 사용하여 시간 간격을 측정하여 시작 시간과 타이머의 메서드 호출 간 간격을 변경한다.
Dispose() Timer의 현재 인스턴스에서 사용하는 모든 리소스를 해제한다.
Dispose(WaitHandle) Timer의 현재 인스턴스에서 사용하는 모든 리소스를 해제하고 타이머가 삭제되면 신호를 보낸다.
DisposeAsync() Timer의 현재 인스턴스에서 사용하는 모든 리소스를 해제한다.

 

 

확장 메서드

ConfigureAwait(IAsyncDisposable, Boolean)  비동기 일회용에서 반환된 작업에 대한 대기가 수행되는 방식을 구성한다.

 

 

Thread safe

이 유형은 Thread-Safety* 이다.

*(스레드 안전(Thread-Safety)이란 멀티 스레드 프로그래밍에서 일반적으로 어떤 함수나 변수, 혹은 객체가 여러 스레드로부터 동시에 접근이 이루어져도 프로그램의 실행에 문제가 없는 것을 말한다)

반응형