'스레드'에 해당되는 글 2건

  1. 2007/07/18 글뻥 C# 쓰레딩 [멀티쓰레딩] (2)
  2. 2007/07/12 글뻥 C# 쓰레딩 [시작과 종료]
지난번에 Thread를 왜 쓰레드라고 표기한지에 대해서와 단일 쓰레드의 시작과 종료에 대해 썰을 풀었다.
이번에는 멀티 쓰레드와 동기화를 함해보고 담에는 쓰레드 풀에 대해 썰을 풀어보자.

using System;
using System.Threading; 

//데이터를 주고받아야 하니 Class를 하나 만들고 인터페이스도 만들어 두자.
class work{
  int a; //받을 인자값

  //인터페이스 메소드
  public work(int a){
   this.a = a;
  }
  
  //실제 일할놈
  public void runit(){
   for (int i=0; i<10; i++){
    Console.WriteLine("Thread{0} Running : {1}", a, i);
    Thread.Sleep(100);
   }
  }
}

//메인쓰레드가 있는 클래스
class Test {
  static void Main(){ 
   Console.WriteLine("쓰레드 시작");
   work wk1 = new work(1); //1로 지정
   work wk2 = new work(2); //2로 지정
   ThreadStart td1 = new ThreadStart(wk1.runit); //시작쓰레드 선언하고
   ThreadStart td2 = new ThreadStart(wk2.runit);
   Thread t1 = new Thread(td1); //돌릴준비하고
   Thread t2 = new Thread(td2);
   t1.Start(); //돌리자
   t2.Start();
  }
}

사용자 삽입 이미지
실행후 1번과 2번 쓰레드가 동시에 작동한다.

그런데 1번보다 2번 쓰레드가 중요하다던가 하는 상황에서는 어떻게 하면 될까?
그때는 "ThreadPriority"메소드를 사용하여 우선순위를 지정할 수 있다.

using System;
using System.Threading; 
class work{
  int a;
  public work(int a){
   this.a = a;
  }
  
  public void runit(){
   for (int i=0; i<10; i++){
    Console.WriteLine("Thread{0} Running : {1}", a, i);
    Thread.Sleep(100);
   }
  }
}
class Test {
  static void Main(){ 
   Console.WriteLine("쓰레드 시작");
   work wk1 = new work(1);
   work wk2 = new work(2);
   ThreadStart td1 = new ThreadStart(wk1.runit);
   ThreadStart td2 = new ThreadStart(wk2.runit);
   Thread t1 = new Thread(td1);
   Thread t2 = new Thread(td2);
   t1.Priority = ThreadPriority.Lowest; //이 부분 추가됨. 1번 쓰레드 우선 순위 최하
   t2.Priority = ThreadPriority.Highest; //이 부분 추가됨. 2번 쓰레드 우선 순위 최고
   t1.Start();
   t2.Start();
  }
}

1번 쓰레드에 우선 순위를 최하로 부여하고 2번 쓰레드에는 우선 순위를 올려 보았다.
(설정은 "Highest, AboveNormal, Normal, BelowNormal, Lowest"로 5단계로 설정할 수 있다.)
사용자 삽입 이미지
본 코드가 적용되기전의 결과와는 다르게 2번 쓰레드가 먼저 생성되고 종료된다.
그러나 믿지는 말자. 인텔 계열의 CPU는 0부터 31까지의 값을 가지고 있고 이는 윈도우에서 사용하는 우선 순위나 별반 다르지 않다.

* 작업관리자에서 우선순위를 설정해 보신분들은 금방 알아볼 것이다. 다음의 그림처럼...
사용자 삽입 이미지
암튼 지맘이니까 믿지는 말자. 쓰레드의 위험성은 이처럼 결과를 예측하고 그 예측이 맞을것이라 바라는것 되겠다. 절대 하지말아야 할 주의점 이다.

이렇게 멀티로 작업을 하다보면 공통 변수로 작업해야 할때가 있다. 이때 여러개의 쓰레드가 1개의 값을 건드리다보면 변수의 값이 엉뚱하게 나오기도 한다.

using System;
using System.Threading; 
class work{
  public int a;
  public void runit(){
   int tp = a + 1;
   Console.WriteLine(tp.ToString());
   Thread.Sleep(10);
   a = tp;   
  }
}
class Test {
  static void Main(){ 
   Console.WriteLine("쓰레드 시작");
   work wk = new work();
   Thread[] td = new Thread[5];
   for (int i=0; i<5; i++){
   td[i] = new Thread(new ThreadStart(wk.runit));
   td[i].Start();
   }
   Thread.Sleep(1000);
   Console.WriteLine("최종값:{0}",wk.a);
  }  
}

요녀석을 실행함 해보자.
사용자 삽입 이미지
결과값은 분명 5가 나와야 하지만 그렇지 않고 1로 고정이 되어버렸다.
다음과 같이 lock이란 녀석을 한번 넣어보자.
using System;
using System.Threading; 
class work{
  public int a;
  public void runit(){
   lock(this){ //바로 여기
   int tp = a + 1;
   Console.WriteLine(tp.ToString());
   Thread.Sleep(10);
   a = tp;   
    }
  }
}
class Test {
  static void Main(){ 
   Console.WriteLine("쓰레드 시작");
   work wk = new work();
   Thread[] td = new Thread[5];
   for (int i=0; i<5; i++){
   td[i] = new Thread(new ThreadStart(wk.runit));
   td[i].Start();
   }
   Thread.Sleep(1000);
   Console.WriteLine("최종값:{0}",wk.a);
  }  
}


실행을 하면 다음과 같이 정상값으로 나온다.
사용자 삽입 이미지
lock이란것으로 동시에 호출하는 쓰레드에 대해 작업중이니 기다리라는 명령을 내릴 수 있는것이다. 그러나 기능의 다양성을 원한다면 lock보다는 "Monitor.Enter()"와 "Monitor.Exit()"를 써주기 바란다.

  public void runit(){
   Monitor.Enter(this);
   int tp = a + 1;
   Console.WriteLine(tp.ToString());
   Thread.Sleep(10);
   a = tp;   
    Monitor.Exit(this);
  }
2007/07/18 11:46 2007/07/18 11:46

쓰레드라고 하는것이 한때는 고수들의 전유물이었는데 요즘은 강호고수들이 많아져서인지 아무나 쓰는 기술되었다.
뭐 암튼 대충 쓰레드에 대해 정리하자는 차원에서 써둠을 밝히니 향후에 제대로 안된다고 이런거 하지말자.

1. 쓰레드 사용하기
일단 닷넷의 쓰레드는 굉장히 쓰기쉽다.
다음의 예제를 함해보자.

using System;
using System.Threading;  //쓰레드를 쓰겠다고 선언하자.

class Test {
  static void Main(){ 
   Console.WriteLine("카운트 0부터 49까지 세기!");
   ThreadStart th = new ThreadStart(work); //1.work메소드를 위임하자.
   Thread t = new Thread(th); //2.쓰레드생성하자.
   t.Start(); //3.시작
   Console.WriteLine("끝!");
  }
  public static void work(){
   for (int i = 0; i<50; i++){
    Console.WriteLine("Conut:{0}",i);
   }
  }
}

결과를 보면 짜잔!
사용자 삽입 이미지

* Ultraedit에서 컴파일하고 실행한 결과창임. 이렇게 하고싶으신분들은 본 블로그 잘뒤져보면 나옴.

2. 쓰레드 중지하기
쓰레드를 중지하기위해서는 2가지 방법이 있다.
- Abort()
- Join()
Abort()는 강제종료이므로 어디서 끝날지 아무도 모른다. 신도 모른다.
Join()은 쓰레드가 다 실행될때 까지 기다렸다가 종료시킨다.
다음예제를 보자

using System;
using System.Threading; 

class Test {   static void Main(){    Console.WriteLine("카운트 0부터 1만까지 세기!");    ThreadStart th = new ThreadStart(work);    Thread t = new Thread(th);    t.Start(); //시작    t.Abort(); //강제종료    Console.WriteLine("끝!");   }   public static void work(){    for (int i = 0; i<10000; i++){     Console.WriteLine("Conut:{0}",i);    }   } }


이녀석을 실행해보면 Abort()때문에 이렇게 된다.
사용자 삽입 이미지

코드에서는 1만까지 진행하는것으로 만들어졌지만 강제종료되어 8524에서 종료되었다.
한번 더 해보자.

사용자 삽입 이미지
어쩌구리.. 이번에는 다 돌아 버렸다... ㅡㅡ;; 암튼 이런식으로 예측이 불가능한 코드가 되어버린다. 중간에 종료하는것은 왠만하면 하지말고 Join()을 사용하도록 하자.
위코드에서 다음과 같이 수정한다.
   ...전략...
   t.Start(); //시작
   t.Join(); //이전에 t.Abort()임
   Console.WriteLine("끝!");
   ...후략...

사용자 삽입 이미지
이번에는 다 돈다. (사실은 위의 이미지와 같은 이미지임.. 흐흐흐)

3. 쓰레드의 쉬게하기
이번에는 일하다가 중간에 쉬게 해보자.
using System;
using System.Threading; 

class Test {   static void Main(){    Console.WriteLine("쓰레드 시작");    ThreadStart th = new ThreadStart(work);    Thread t = new Thread(th);    t.Start();    Console.WriteLine(t.ThreadState);    Console.WriteLine("끝!");   }   public static void work(){    Thread.Sleep(100);   } }


사용자 삽입 이미지
쓰레드가 시작되고 Sleep명령으로 인해 Sleep모드로 들어갔다.

명령이 주어질때까지 중지하고 싶다면 Suspend()를 사용하자. Suspended된놈을 다시 살리는 것은 Resume()이 있는데 이건 알아서 한번 만들어 보도록 하자.

결론적으로 .NET의 쓰레드(Thread)는 다음과 같은 상태값을 가진다.
(ThreadState()로 나오는 결과값이 바로 타원형안에 있는 녀석들이다.)

사용자 삽입 이미지
이 표만 잘봐두면 쓰레드 어려운것이 아니다.
일단 생성된 쓰레드는 Unstarted라는 값을 가진다. Start()라는 메소드로 Started라는 상태값을 가지게 되는 것이다. 다시말해 타원안에 있는 것은 상태값, 화살표에 있는 것이 바로 메소드 되겠다.

다음에는 멀티 쓰레드 함 해보자.

* 본 게시물에서 사용한 쓰레드라는 표현은 "Thread"의 한음표현이며 쓰레드는 스레드라고도 표기됩니다. Microsoft공식학습서 Inside C# 2nd Ed.에는 쓰레드라고 표기되어 있어 본 게시물도 쓰레드라고 표현함을 알려드립니다.

2007/07/12 16:20 2007/07/12 16:20