블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2794)
Unity3D (852)
Programming (478)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (185)
협업 (11)
3DS Max (3)
Game (12)
Utility (68)
Etc (98)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (55)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
지난번에 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);
  }

반응형
Posted by blueasa
, |