일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 윈도우폰
- 실버라이트 코리아
- 신석현
- 훈스닷넷
- 쉐어포인트코리아
- 윈도우 모바일
- 안드로이드
- 거제도
- 루나네스
- MIX10
- 헤이맨
- 마이크로소프트
- 김춘배
- UX베이커리
- 옴니아2
- 윈도우모바일
- 소년포비소프트
- 소년포비
- 주신영
- windows mobile 6.5
- 신동혁
- 데브피아
- 황광진
- 윈도데브
- 윈도우폰7
- 윈모데브
- winmodev
- 스마트폰
- 서진호
- 지승욱
- Today
- Total
소년포비의 세계정복!!
[C#] 세가지 Timer 와 그 차이점 본문
특정 작업을 주기적으로 실행하기 위해 흔히 Timer 객체를 사용합니다
정해진 시간 간격으로 변수를 업데이트 한다던지, 모니터링 한다던지, 로그를 기록 한다던지, 그 작업 내용은 무궁무긴 하겠죠
Timer 객체는 이러한 주기적 작업을 아주 쉽게 처리해 주는, 닷넷 프레임워크에서 제공하는 고마운 객체입니다
그러나 한가지 생각해 볼 문제가 있네요..
닷넷 프레임워크에는 무려 3가지 서로 다른 Timer 를 제공하고 있다는 겁니다. 바로 아래 3가지 Timer 입니다
1. System.WIndows.Forms.Timer
2. System.Threading.Timer
3. System.Timers.Timer
닷넷이 이 3가지 Timer 를 각각 제공하는 이유가 무엇일까요?
필자는 이 문제(?)에 대해, 몇 년전에 의구심을 가졌읍니다만, 당시 의구심만 가진채 그냥 세월을 보내 버렸습니다 --;
그리고는 대략 아는 지식으로 대략 적절 할 것 같은(?) Timer을 사용해 왔던 것 같습니다
게을렀던 거죠. 의구심이 들면 파고들어 정복하는 사람이 성공합니다. ㅋㅋ , 기술이든 인생이든...
예기가 다른 길로 세네요.. ㅎ,
우선 이 세가지 서로다른 Timer 의 msdn 설명을 볼까요
사용할 수 있도록 최적화되었으며 창에서 사용해야 합니다 지정된 간격으로 메서드를 실행하는 메커니즘을 제공합니다
3) System.Timers.Timer 응용 프로그램에 되풀이 이벤트를 생성합니다
|
msdn 설명을 봐도,
'System.WIndows.Forms.Timer 가 윈도우 응용프로그램에 최적화 되었다' 라는 말 빼고는 거의 차이점을 느낄 수 없네요
물론 msdn은 보다 상세한 내용을 더 기술되어 있습니다만, 이 글에서는 이 세가지 Timer 의 차이점을 크게 두 가지 측면에서
살펴 볼까 합니다
1. 사용법상의 차이점
2. 수행되는 Thread 환경의 차이점
* 사용법의 차이
먼저 사용법의 차이를 알아보죠
사용법의 차이는 말 그대로 사용법입니다. 이것이 원리는 아니죠.
원리가 다르기 때문에 사용법이 다른 것이지, 사용법이 다르기 때문에 원리가 다른건 아닙니다
그럼에도, 사용법 차이점부터 알아 보는 것은.......... 쉽기 때문이죠 ^^;
(개발자 여러분, 사용법만 익히지 말고 원리를 익힙시다)
1. System.Windows.Forms.Timer 사용법
윈도우 응용프로그램 개발자들에겐 아마 가장 익숙한 Timer 일 것입니다
- 객체 생성
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
- 반복 주기 및 작업 설정
timer.Interval = 1000; //주기 설정
timer.Tick += new EventHandler(timer_Tick); //주기마다 실행되는 이벤트 등록
void tmrWindowsFormsTimer_Tick(object sender, System.EventArgs e)
{
//수행해야할 작업
}
- Timer 시작
timer.Enable = true 또는 timer.Start();
- Timer 중지
timer.Enable = false 또는 timer.Stop();
2. System.Threading.Timer 사용법
- 객체 생성
Timer 객체를 생성할 때, 반복적으로 실행하게 될 메서드를 콜백 메서드로 등록해야 합니다
System.Threading.Timer timer = new System.Threading.Timer(CallBack);
- 반복 주기 및 작업 설정
이 Timer 에는 Change 메서드가 있는데, 이 메서드는 dueTime과 period 를 입력받습니다
dueTime은 Timer 가 시작하기 전 대기(지연)시간이며 period는 반복 주기입니다
timer.Change(0, 1000);
그리고 반복 실행 작업이,
윈도우 응용프로그램의 UI Thread와 연관된다면, Cross Thread 문제가 발생하기 때문에 Invoke나 BeginInvoke를
통해 핸들링 해야 합니다.
앞서, Timer 객세 생성시 등록한 콜백 메서드에서 BeginInvoke를 통해 UI 쓰레드를 핸들링 할 수 있습니다
delegate void TimerEventFiredDelegate();
void CallBack(Object state)
{
BeginInvoke(new TimerEventFiredDelegate(Work));
}
private void Work()
{
//수행해야할 작업(UI Thread 핸들링 가능)
}
- Timer 시작
위의 Change 메서드의 dueTime 이 0 이므로 그 즉시 시작된다. Start와 같은 별도의 시작 명령이 존재하지 않음
- Timer 중지
timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
dueTime와 period 를 무한대로 잡아서 Timer 가 실행되지 않도록 하는 것이 중지하는 것과 같습니다
3. System.Timers.Timer 사용법
- 객체 생성
System.Timers.Timer timer = new System.Timers.Timer();
- 반복 주기 및 작업 설정
timer.Interval = 1000;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); //주기마다 실행되는 이벤트 등록
이 Timer 역시 UI Thread를 핸들링 하기 위해서 Invoke 나 BeginInvoke를 이용해야 합니다
delegate void TimerEventFiredDelegate();
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
BeginInvoke(new TimerEventFiredDelegate(Work));
}
private void Work()
{
//수행해야할 작업(UI Thread 핸들링 가능)
}
- Timer 시작
timer.Enable = true 또는 timer.Start();
- Timer 중지
timer.Enable = false 또는 timer.Stop();
결론적으로 보면,
Timer 객체의 사용법 자체는 그리 어렵지 않습니다. 또한 세 가지 Timer 의 사용법은 대동소이 함을 알 수 있습니다
다만 윈도위 응용프로그램에서 Timer 를 사용할 때 System.WIndows.Forms.Timer 를 제외하고는
UI Thread 에서 만들어진 컨트롤에 접근하려면 크로스 쓰레드 문제가 있으므로 마샬링 된 호출(Invoke / BeginInvoke) 를
이용해야 하는 차이점이 있습니다
msdn의 설명처럼 System.Windows.Forms.Timer 는 윈도우 응용프로그램에 최적화 되어 있나 보네요..
그럼 왜 System.Windows.Forms.Timer 는 크로스쓰레드 문제가 발생하지 않을까요?
그리고 정말 사용법 처럼 크게 차이가 나지 않는 걸까요?
다음에 설명할, 두번째 관점인 '수행되는 Thread 환경의 차이점'에서 이를 알아보도록 하죠
* 수행되는 쓰레드(Thread) 환경의 차이
앞서 사용법에서 UI Thread 라는 말을 했습니다
윈도우 응용프로그램을 예로 들어, 버턴이나 각종 컨트롤이 생성되고 핸들링 되는 것은 UI Thread 상에서 이루어집니다
이와 다른 개념이 Work Thread 인데요, 기본 쓰레드(Default Thread) 이외에
개발자가 별도의 쓰레드를 생성하여 작업을 실행한다면 이는 Work Thread(작업자 쓰레드) 라 합니다
또한 UI Thread 입장에서는, 닷넷의 ThreadPool 에 의해 실행되는 쓰레드도 Work Thread 로 볼 수 있습니다
쓰레드가 다르다면 쓰레드의 고유번호도 당연히 다릅니다
System.Threading.Thread.CurrentThread.IsThreadPoolThread 속성은 현재 쓰레드의 고유 식별자 값을 가져 옵니다
우린 이 속성을 통해 Timer 객체가 수행되는 쓰레드를 알아 보도록 하겠습니다
1. System.Windows.Forms.Timer 의 쓰레드 환경
윈도우 응용프로그램에 최적회 되어 있다는 이 Timer 는 윈도우 응용프로그램 기본 쓰레드와 동일한 쓰레드 상에서 동작합니다
이를 확인하기 위해, 다음과 같이 코드 중간에 IsThreadPoolThread 속성을 확인해 봅니다
- 기본 쓰레드의 고유 번호를 확인한다
윈도우응용프로그램 생성자나 기타 이벤트에서 아래 코드를 기입합니다
MessageBox.Show(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
- Timer 쓰레드의 고유번호를 확인한다
Timer 의 Tick 이벤트에서 다음의 코드를 기입합니다
void timer1_Tick(object sender, EventArgs e)
{
MessageBox.Show(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
//수행해야할 작업
}
이렇게 확인 해 보면 두 쓰레드는 동일한 고유번호를 반환하게 됩니다
이 말은 곧, 윈도우응용프로가램의 기본 쓰레드인 UI Thread 상에서 Timer이 동작한다는 것을 짐작할 수 있습니다
즉 멀티 쓰레드 환경이 아닌 것이죠
예로, Tick 이벤트에 시간이 긴~ 작업이 수행된다면 프로그램은 그 시간 동안 블럭 된 대기 한다는 것입니다
Timer 의 동작이 기본 프로그램 동작과 독립적으로 수행된다고 생각하시면 안됩니다
2. System.Threading.Timer 의 쓰레드 환경
역시 앞서와 같이 기본 쓰레드와 Timer 쓰레드의 고유번호를 확인 해 봅니다
- 기본 쓰레드의 고유 번호를 확인한다
윈도우응용프로그램 생성자나 기타 이벤트에서 아래 코드를 기입합니다
MessageBox.Show(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
- Timer 쓰레드의 고유번호를 확인한다
CallBack 메서드에서 다음과 같이 코드를 기입합니다
void CallBack(Object state)
{
MessageBox.Show(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
BeginInvoke(new TimerEventFiredDelegate(Work));
}
어떻습니까? 두 쓰레드는 다른 고유번호를 반환하지요
즉 UI Thread 와 다른 쓰레드, 즉 Work Thread(작업자 쓰레드)임을 알 수 있습니다
이는 곧 멀티 쓰레드가 된 셈이죠. 두 쓰레드는 서로 독립적으로 수행될 것입니다
앞서, System.Windows.Forms.Timer 객체와는 달리 CallBack 메서드에 시간이 오래 걸리는 작업을 수행해도
프로그램이 대기상태로 빠지는 않죠. Timer 동작이 기본 프로그램의 동작과는 독립적으로 수행되는 것이죠.
참고로 이 Timer 는 닷넷의 ThreadPool(쓰레드풀) 에서 관리합니다
3. System.Timers.Timer 의 쓰레드 환경
결론부터 말하자만, 이 Timer 는 기본 쓰레드에서 수행될 수도 있고, 작업자 쓰레드에서 수행될 수도 있습니다
만일, SynchronizingObject 속성을 폼객체로 한다면 Timer는 UI 쓰레드 상에서 동작할 것이며
이 속성을 지정하지 않는다면, 작업자 쓰레드 상에서 동작하게 됩니다
아래와 같이 SynchronizingObject 속성의 설정 여부에 따른 ManagedThreadid 값을 확인해 보기 바랍니다
timer.SynchronizingObject = this;
타이머 쓰레드의 고유번호를 알기 위해 Elapsed 이벤트에
MessageBox.Show(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
를 확인해 보세요
---
결국 Timer 의 실행이 기본 쓰레드에서 하느냐, 작업자 쓰레드 에서 하느냐에 차이인데요,
앞서, 사용법의 차이를 살펴 봤을 때 System.Windows.Forms.Timer 객체를 제외하고는 윈도우응용프로그램의 UI 컨트롤
핸들링 시 크로스 도메인 문제가 발생했던 원인이 되는 것입니다
* 기타 차이점 및 요약, 참조
아래 표는 msdn magazine에 소개된 세 Timer 의 차이점에 대한 표입니다
우리가 알아 본 내용 이외에도, 쓰레드 안정성(동기화 문제)에 대한 내용도 있습니다
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> |
System.Windows.Forms |
System.Timers |
System.Threading |
Timer event runs on what thread? |
UI thread |
UI or worker thread |
Worker thread |
Instances are thread safe? |
No |
Yes |
No |
Familiar/intuitive object model? |
Yes |
Yes |
No |
Requires Windows Forms? |
Yes |
No |
No |
Metronome-quality beat? |
No |
Yes* |
Yes* |
Timer event supports state object? |
No |
No |
Yes |
Initial timer event can be scheduled? |
No |
No |
Yes |
Class supports inheritance? |
Yes |
Yes |
No |
* Depending on the availability of system resources (for example, worker threads) |
마지막으로 msdn의 설명을 옮기며 마칩니다
'프로그램 세상 > C#' 카테고리의 다른 글
[C#] 체중 관리 프로그램 (0) | 2009.10.22 |
---|---|
[C#] 외부 응용프로그램 실행 (0) | 2009.10.22 |
[C#] WIN32 API를 이용 (0) | 2009.10.14 |
[C#] 전광판처럼 움직이는 라벨 (0) | 2009.10.13 |
[C#] DB에 이미지저장하고 불러오기 (0) | 2009.10.12 |