쓰레드 ( Thread )   쓰레드 란 CPU 를 이용 하 는 가장 작 은 단위 인데 싱글 쓰레드 를 사용 하 면 CPU 의 사용 권한 을 하나 의 쓰레드 가 독차지 하 게 된다 . 지하철 개찰구 의 예 를 들 면 개찰구 가 하나 라면 평상시 에 는 큰 무리 가 아니 지만 출퇴근 시간 에 는 무리 가 따를 수 있 다 . 결국 개찰구 를 늘 여야 한다는 것 이 다 . 프로그래밍 에서 볼 때 개찰구 를 늘이 는 것 이 멀티 쓰레드 를 이용 하 는 것 이 다 . 멀티 쓰레드 가 제대로 동작 하 기 위해서 는 CPU 가 여러 개 있 어야 한다 . 보통 은 단일 CPU 를 사용 할 것 이 다 . CPU 는 한 번 에 하나 의 쓰레드 를 사용 하 므로 멀티 쓰레드 프로그램 이 실행 되 는 경우 에 는 CPU 의 사용 시간 을 나누 어서 각각 의 쓰레드 에게 나누 어 주 는 것 이 다 . 결국 개찰구 는 늘였 지만 표 를 파 는 곳 은 한 군데 인 것 이 다 .   C # 에서 의 멀티 쓰레드   C # 에서 멀티 쓰레드 를 사용 하 는 방법 은 기 정의 된 쓰레드 클래스 를 사용 하 면 된다 . 결국 배워야 하 는 것 은 C # 에서 멀티 쓰레드 를 위한 클래스 가 어떤 것 이 있 고 그 사용법 은 어떻게 되 는가 이 다 . 쓰레드 를 위한 개체 들 은 System . Threading 네임 스페이스 안 에 정의 되 어 있 다 .   [ 첫 번 째 예제 ]   using System ;   using System . Threading ;   public class ThreadTest   {   public void FirstWork ( )   {   for ( int i = 0 ; i < 100 ; i ++)   {   Thread . Sleep ( 1000 ) ; / / 밀리 세컨드 단위   Console . Write ( " F { 0 } " , i ) ;   }   }   public void SecondWork ( )   {   for ( int i = 0 ; i < 100 ; i ++)   {   Thread . Sleep ( 1000 ) ;   Console . Write ( " S { 0 } " , i ) ;   }   }   [ MTAThread ]   public static void Main ( )   {   ThreadTest t = new ThreadTest ( ) ;   / / Thread 는 생성자 에 ThreadStart 형 Delegate 를 인자 로 받 는다 .   Thread first = new Thread ( new ThreadStart ( t . FirstWork ) ) ;   Thread second = new Thread ( new ThreadStart ( t . SecondWork ) ) ;   first . Start ( ) ;   second . Start ( ) ;   }   }   [ 예제 1 - 1 ]   using System ;   using System . Threading ;   class ThreadTest   {   static void Thmethod ( )   {   int id = AppDomain . GetCurrentThreadId ( ) ;   Console . WriteLine ( " Thread [ { 0 }] Thmethod Method Running ", id ) ;   }   static void Main ( )   {   int id = AppDomain . GetCurrentThreadId ( ) ;   Console . WriteLine ( " Main Thread [ { 0 }]", id ) ;   for ( int i = 0 ; i < 10 ; i ++)   {   Thread th = new Thread ( new ThreadStart ( Thmethod ) ) ;   th . Start ( ) ;   }   }   }   Thread . Sleep 안 에 는 해당 Thread 가 얼마 만큼 쉴 건지 에 대한 시간 을 밀리 세컨드 단위 로 지정 한다 . 만약 시간 을 0 으로 설정 하 면 현재 자신 에게 주어진 시간 을 다른 쓰레드 에게 쓰 게 하 겠 다는 의미 이 다 . 지금 당장 은 CPU 를 사용 하 지 않 아도 될 때 다른 쓰레드 에게 CPU 를 사용 할 기회 를 줌 으로써 CPU 를 효율 적 으로 이용 할 수 있 다 . 쓰레드 를 쉐 게 하 는 방법 은 Thread . Suspend 를 이용 할 수 도 있 다 . Sleep 과 의 차이 는 Sleep 인 경우 엔 지정 한 시간 만큼 쉰다는 의미 지만 Suspend 인 경우 엔 Resume 메소드 를 호출 할 때 까지 쉬 게 된다는 것 이 다 . 또 다른 차이점 은 Sleep 메소드 는 자기 자신 의 쓰레드 만 쉬 게 할 수 있 다 . 반면 에 Suspend 는 자기 뿐 아니 라 다른 쓰레드 도 쉬 게 할 수 있 다 . 잠 을 자 고 있 는 Thread 가 스스로 깰 수 는 없 다 . 그래서 Suspend 로 쉬 고 있 는 쓰레드 는 다른 쓰레드 가 Resume 을 이용 하 여 깨울 때 까지 쉬 고 있 는 것 이 다 . 주의 할 점 은 Sleep 인 경우 는 쓰레드 가 즉시 중단 되 지만 Suspend 로 쉬 게 할려면 즉시 중단 되 지 않 는다 .   [ 예제 2 ]   using System ;   using System . Threading ;   public class ThreadTest 2   {   public bool sleep = false ;   public void FirstWork ( )   {   for ( int i = 0 ; i < 10 ; i ++)   {   Console . WriteLine ( " F { 0 }", i ) ;   if ( i == 5 )   {   sleep = true ;   Console . WriteLine ( "");   Console . WriteLine ( " first 쉼 . ..");   Thread . CurrentThread . Suspend ( ) ;   }   }   }   }   class TestMain   {   [ MTAThread ]   public static void Main ( )   {   ThreadTest 2 t = new ThreadTest 2 ( ) ;   Thread first = new Thread ( new ThreadStart ( t . FirstWork ) ) ;   first . Start ( ) ;   while ( t . sleep == false ) {}   Console . WriteLine ( "");   Console . WriteLine ( " first 를 깨 웁 니다 . ..");   first . Resume ( ) ;   }   }   Suspend 메소드 로 쓰레드 를 잠시 중지 하 면 Resume 메소드 로 다시 동작 하 게 할 수 있 지만 Thread . Abort 로 일단 쓰레드 를 종료 시키 면 다시 되살릴 수 없 다 . 쓰레드 가 확실히 종료 되 었 는지 를 살펴보 기 위해서 는 Thead . Join 메소드 를 사용 할 수 있 는데 Thread . Join 메소드 는 동기 적 으로 동작 하 므로 쓰레드 가 종료 할 때 까지 기다리 게 된다 . 만일 어떤 이유 에서 든지 쓰레드 가 종료 되 지 않 는 다면 무한정 기다릴 수 밖 에 없 다 . Thread . Join 메소드 안 에 1 / 1000 초 단위 로 파라미터 를 전달 할 수 있 는데 이것 은 얼마 만큼 Join 으로 붙 은 쓰레드 가 종료 될 때 까지 기다릴 수 있 는 가 에 대한 값 이 다 . 만일 주어진 시간 안 에 종료 되 면 true 를 반환 하 고 기다리 기 를 중지 한다면 false 값 을 반환 한다 .   쓰레드 가 여러 개 있 다면 한 쓰레드 가 동작 하 고 나 서 어떤 쓰레드 가 동작 할까 ? 아마도 높 은 우선 순위 를 가지 고 있 는 쓰레드 가 수행 될 것 이 다 . 각각 의 쓰레드 는 CPU 사용 권한 에 대한 우선 순위 가 있 는데 우선 순위 가 높 을수록 CPU 사용 권한 을 먼저 할당 받 는다 .   아래 의 예제 를 보 도록 하 자 .   using System ;   using System . Threading ;   public class ThreadTest 3   {   public bool sleep = false ;   public void FirstWork ( )   {   for ( int i = 0 ; i < 10 ; i ++)   {   for ( int j = 0 ; j < 10 ; j ++)   {   Thread . Sleep ( 100 ) ;   Console . Write ( ",");   }   Console . WriteLine ( " F { 0 }", i ) ;   }   }   public void SecondWork ( )   {   for ( int i = 0 ; i < 10 ; i ++)   {   for ( int j = 0 ; j < 10 ; j ++)   {   Thread . Sleep ( 100 ) ;   Console . Write ( ",");   }   Console . WriteLine ( " S { 0 }", i ) ;   }   }   }   class TestMain   {   [ MTAThread ]   public static void Main ( )   {   ThreadTest 3 t = new ThreadTest 3 ( ) ;   Thread first = new Thread ( new ThreadStart ( t . FirstWork ) ) ;   Thread second = new Thread ( new ThreadStart ( t . SecondWork ) ) ;   first . Start ( ) ;   second . Start ( ) ;   }   }   위 의 예제 를 실행 해 보 면 각각 의 쓰레드 가 할당 받 은 시간 이 비슷 함 을 알 수 있 다 . 두 개 의 쓰레드 가 우선 순위 가 비슷 하 니까 아래 의 그림 과 같 은 결과 가 나오 는 것 이 다 .   아래 의 예 는 Join 을 이용 한 예제 이 다 .   first . Join ( ) 부분 을 주석 으로 막 은 후 다시 실행 해 보 라 .   using System ;   using System . Threading ;   public class ThreadTest 2   {   public int [ ] iArray = new int [ 100 ] ;   public void CollectData ( )   {   for ( int i = 0 ; i <= 20 ; i ++)   {   iArray [ i ] = i + 1 ;   Console . Write ( ",");   Thread . Sleep ( 500 ) ;   }   }   }   class TestMain   {   [ MTAThread ]   public static void Main ( )   {   ThreadTest 2 t = new ThreadTest 2 ( ) ;   Thread first = new Thread ( new ThreadStart ( t . CollectData ) ) ;   first . Start ( ) ;   first . Join ( ) ;   int sum = 0 ;   for ( int i = 0 ; i {   sum += t . iArray [ i ] ;   }   Console . WriteLine ( ) ;   Console . WriteLine ( " sum = { 0 }", sum ) ;   }   }   한 쓰레드 에 대해 우선 순위 를 높여 주 면 CPU 사용 권한 을 우선 적 으로 갖 는 것 이 다 . Thread 의 우선 순위 와 관련 된 프로 퍼티 가 있 는데 열거 형 값 인 Highest , AboveNormal , Normal , BelowNormal , Lowest 중 한 값 이 다 . 아래 의 예제 를 살펴 보 자 .   using System ;   using System . Threading ;   public class ThreadTest 3   {   public bool sleep = false ;   public void FirstWork ( )   {   for ( int i = 0 ; i < 10 ; i ++)   {   for ( int j = 0 ; j < 10 ; j ++)   {   Thread . Sleep ( 100 ) ;   Console . Write ( ",");   }   Console . WriteLine ( " F { 0 }", i ) ;   }   }   public void SecondWork ( )   {   for ( int i = 0 ; i < 10 ; i ++)   {   for ( int j = 0 ; j < 10 ; j ++)   {   Thread . Sleep ( 100 ) ;   Console . Write ( ",");   }   Console . WriteLine ( " S { 0 }", i ) ;   }   }   }   class TestMain   {   [ MTAThread ]   public static void Main ( )   {   ThreadTest 3 t = new ThreadTest 3 ( ) ;   Thread first = new Thread ( new ThreadStart ( t . FirstWork ) ) ;   Thread second = new Thread ( new ThreadStart ( t . SecondWork ) ) ;   first . Priority = ThreadPriority . Lowest ;   first . Start ( ) ;   second . Start ( ) ;   }   }   멀티 쓰레드 환경 인 경우 여러 곳 에서 같 은 객체 의 메소드 를 호출 하 는 경우 에 예기 치 않 은 결과 가 나타날 수 있 다 . 어떤 메소드 의 사용 을 한 쓰레드 가 끝난 후 다른 쓰레드 가 접근 하 게 하 려면 lock 문 을 사용 한다 . 다음 의 예제 를 보 도록 하 자 .   using System ;   using System . Threading ;   public class ThreadTest 3   {   public string lockString = " Hello ";   public void Print ( string rank )   {   / / lock 을 걸 어 준 구문 은 처음 쓰레드 가 끝 날 때 까지 다른 쓰레드 가 접근 금지   lock ( this )   {   for ( int i = 0 ; i < 10 ; i ++)   {   for ( int j = 0 ; j < 10 ; j ++)   {   Thread . Sleep ( 100 ) ;   Console . Write ( ",");   }   Console . WriteLine ( "{ 0 }{ 1 } ", rank , lockString ) ;   }   }   }   public void FirstWork ( )   {   Print ( " F ");   }   public void SecondWork ( )   {   Print ( " S ");   }   }   class TestMain   {   [ MTAThread ]   public static void Main ( )   {   ThreadTest 3 t = new ThreadTest 3 ( ) ;   Thread first = new Thread ( new ThreadStart ( t . FirstWork ) ) ;   Thread second = new Thread ( new ThreadStart ( t . SecondWork ) ) ;   first . Start ( ) ;   second . Start ( ) ;   }   }   lock 문 이외 에 System . Monitor 라는 클래스 가 있 는데 이 Monitor 클래스 에 는 Enter , Exit 메소드 가 있 는데 Enter 메소드 는 잠금 상황 으로 , Exit 메소드 는 잠금 을 해제 하 는 역할 을 한다 . 앞 에서 작성 한 예제 를 System . Monitor 를 이용 하 는 예문 으로 바꿔 보 자 …   using System ;   using System . Threading ;   public class ThreadTest 3   {   public string lockString = " Hello ";   public void Print ( string rank )   {   / / lock 을 걸 어 준 구문 은 처음 쓰레드 가 끝 날 때 까지 다른 쓰레드 가 접근 금지   Monitor . Enter ( this ) ;   for ( int i = 0 ; i < 10 ; i ++)   {   for ( int j = 0 ; j < 10 ; j ++)   {   Thread . Sleep ( 100 ) ;   Console . Write ( ",");   }   Console . WriteLine ( "{ 0 }{ 1 } ", rank , lockString ) ;   }   Monitor . Exit ( this ) ;   }   public void FirstWork ( )   {   Print ( " F ");   }   public void SecondWork ( )   {   Print ( " S ");   }   }   class TestMain   {   [ MTAThread ]   public static void Main ( )   {   ThreadTest 3 t = new ThreadTest 3 ( ) ;   Thread first = new Thread ( new ThreadStart ( t . FirstWork ) ) ;   Thread second = new Thread ( new ThreadStart ( t . SecondWork ) ) ;   first . Start ( ) ;   second . Start ( ) ;   }   }  