[C# 강좌 21강] 쓰레드 - Timer

공부/C#  2012.09.28 09:00



안녕하세요 개발자 명월입니다.

이번 포스팅에서는 쓰레드에서 가장 많이 사용하는 Timer 를 설명하겠습니다.

Timer 는 C++ 부터 쭈욱 많이 사용되는 스레드 종류 중에 하나로써 C#에서는 Timer 클래스가 3개가 존재합니다.

물론 각각의 Timer 는 속성이 다릅니다.

 

먼저 MSDN 부터 확인해 보겠습니다.

System.Windows.Forms.Timer -> MSDN 바로가기

System.Timer.Timer -> MSDN 바로가기

System.Threading.Timer -> MSDN 바로가기

 

먼저 Timer 의 특징은 Thread와 다르게 선언할 때 반복의 간격을 정하게 되겠습니다. 아무래도 Thread.Sleep는 인터럽트 적으로 강제로 프로세스를 멈추게 하는 성향이 있기 때문에 시스템에 무리가 가게 되어있습니다. 그러나 Timer 는 Callback 개념으로 지정된 시간 후에 Callback을 하는 개념이니 아무래도 부하가 적게 걸립니다.

그리고 Timer는 세개로 나누어져 있습니다. Timer는 ThreadPool 과 비슷한 개념으로 부모 메소드가 차단 되면 Timer도 자동적으로 Callback의 주체가 없어지니 소멸되게 되어있습니다. 그러나 ThreadPool 과는 가장 큰 차이점은 메시지 Callback 개념이라는 것입니다. 즉, windows.forms 에 있는 것은 window 메시지 흐름의 callback을 하는 것이고 시스템 사용자 Time 메시지 흐름의 callback 메시지이고 Thread는 Thread의 콜백입니다.

 

역시 설명보다는 예제가 더 이해하기 쉽겠습니다.

 

먼저 System.Forms.Timer 입니다.

 

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 using System.Windows.Forms;
  5
  6 namespace Blog20120827
  7 {
  8     class Program :Form
  9     {
10         static void Main(string[] args)
11         {
12             Application.Run(new Program());
13         }
14         TextBox _textbox;
15         public Program() {
16             _textbox = new TextBox();
17             _textbox.Size = new System.Drawing.Size(this.Size.Width, 20);
18             this.Controls.Add(_textbox);
19             Timer tm = new Timer();
20             tm.Interval = 1000;
21             tm.Enabled = true;
22             tm.Tick += new EventHandler(tm_Tick);
23
24             this.Click += new EventHandler(Program_Click);  

25         }
26
27         void Program_Click(object sender, EventArgs e)
28         {
29             System.Threading.Thread.Sleep(10000);
30         }
31
32         void tm_Tick(object sender, EventArgs e)
33         {
34             this._textbox.Text = DateTime.Now.ToString();
35         }
36     }
37 }
38

 


먼저 첫번째 확인 할 부분은 tm_Tick 이벤트에서 바로 윈도우 객체 this._textbox.Text에 직접 값을 넣었지만 스레드크로싱 에러가 나오지 않았습니다. 두번째 Form을 클릭을 하면 Thread.Sleep로 폼을 멈추었는데 Thread도 멈추었습니다. 즉 window의 메시지을 타고 있기에 스레드크로싱에러가 나오지 않은 것 입니다. 같은 메시지를 타고 있기 때문입니다. 두번째는 폼 메시지를 강제로 멈추게 하였더니 그의 붙어 있는 메시지까지 멈춰버린 현상입니다.

 

같은 소스로 Timer 만 바꾸어서 디버그 해보겠습니다.

 

 

보시는 바와같이 크로싱 에러가 나옵니다. 물론 크로싱 에러는 Invoke 로 극복이 가능하나 Invoke는 말 그대로 강제 동기화이기 때문에 시스템 저하에 큰 영향을 미치게 되는 것입니다. 결론은 Window 기반의 스레드 에서는 Window.Timer 를 사용해야 한다는 결론이 나오게 되는 것입니다.

 

그럼 두번째의 Timer.Timer Threading.Timer 차이는 서버시간을 쓰느냐 프로그램 시간을 사용하느냐의 차이입니다. 이거는 제가 특별히 프로그램을 나태내기 힘들기에 설명으로 표현하겠습니다.

Threading.Timer 는 프로그램의 리소스의 영향이 갑니다. 즉 프로그램 전체가 인터럽트에 걸리거나 느려지게 되면 이 스레드는 같이 멈추거나 느려지게 되나 Timer.Timer는 시스템 시간에 영향이 가기때문에 즉 프로그램이 인터럽트에 걸리거나 느려져도 Timer 스레드는 그 시간에 맞추어 실행한다는 차이입니다.

 

특별히 시스템을 일부러 인터럽트에 걸리게 하거나 느려지게 하는 프로그램을 만들때 (검사 프로그램등등.) 이 두 스레드의 차이를 두어 작성을 하겠으나 거의 대부분의 프로그램은 그런 경우가 없기에 보통은 Thread.Timer의 스레드를 많이 이용하게 됩니다.

 

필자인 저도 지금까지 경험상 Timer의 Timer를 사용한 적이 없어서 특별히 생각나는 예제가 없어서 설명으로 풀었습니다.

 

앞서 살펴본 Thread를 살펴 보았지만 실질적으로 Thread 중에서 가장 많이 사용하게 되는게 이 Timer들입니다.

특히 C#의 특성상 시스템 개발은 조금 거리가 있고 보통은 Winform을 작성하고 또 Winform 이면 window.Timer 을 가장 많이 사용하기에 잘 살펴보고 지나가야겠습니다.

 

(※ 혹시 Timer 와 Thread의 차이 예제에 대해 아시는 분 계시면 알려주시면 감사하겠습니다.)

 

아래는 Graphic 과 Timer 관계의 예제입니다. 참고로 만들어봤습니다. 확인해 보곘습니다.

 

 

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 using System.Windows.Forms;
  5 using System.Drawing;
  6
  7 namespace Blog20120827
  8 {
  9     class Program :Form
10     {
11         static void Main(string[] args)
12         {
13             Application.Run(new Program());
14         }
15         Timer tm;
16         public Program() {
17             tm = new Timer();
18             tm.Interval = 1;
19             tm.Enabled = true;
20             tm.Tick += new EventHandler(tm_Tick);
21         }
22         double size = 1;
23         double x = 0;
24         double x_ = 0;
25         void tm_Tick(object sender, EventArgs e)
26         {
27             if (size < 30)
28             {
29                 size+=0.1;
30             }
31             else {
32                 x_+=0.5;
33             }
34             x += x_
35             Graphics g = this.CreateGraphics();
36             g.Clear(Color.White);
37             g.DrawString("안녕", new Font("돋움", (int)size), Brushes.Black, new PointF((int)x, 0));
38         }
39     }
40 }
41

 

 

글자가 가까이 점점 다가와서 사라지는 예제 입니다. 자료 첨부하겠습니다. 확인 해 보세요.

 

Blog20120827.zip

 


댓글 5개가 달렸습니다.
댓글쓰기
  1. dreamer
    2012.10.05 22:59 신고 |  수정/삭제  댓글쓰기

    잘봤습니다.ㅎ 머리가 아프네요..
    한번 테스트해보려고 했는데 using에 system.Windows는 죽어라 뒤져도 안나오네요ㅜ
    windows에 대한 정보가 없어서그런지..system.web 밖에 없네요ㅎ
    역시 이제 접하는사람이 스레드를 한방에 이해하기는 힘든가보네요..
    뭐 여러번 보다보면야 언젠가 이해는 가겠지만ㅎ
    강의글 작성하시느라 수고 많으십니다.^^

    • 明月 v명월v
      2012.10.06 08:43 신고 |  수정/삭제

      방문감사합니다.
      옆에 참조는 하셨는지.. 참조추가를 하지 않으면 using에 선언이 되지 않습니다.
      앞으로도 관심 부탁드립니다.

    • dreamer
      2012.10.06 12:10 신고 |  수정/삭제

      아 참조..기존에 windows는 다 등록되있는줄 알았는데 아니었나보네요..
      알려주셔서 감사합니다ㅎㅎ

    • 明月 v명월v
      2012.10.06 16:46 신고 |  수정/삭제

      안녕하세요. 해결 되셨다니 다행이네요.^^

  2. zealot71@naver.com
    2015.08.18 01:22 신고 |  수정/삭제  댓글쓰기

    혹시 멀티 쓰레드를 돌리는 프로그램을 24시간정도 돌리다가 하나가 죽는 상황이 있는데 이러한 경우가 어떤 특별한 경우 또는 이유가 있는지 궁금합니다.