메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

C# 쓰레드 이야기: 5. NT vs UNIX

한빛미디어

|

2001-11-27

|

by HANBIT

16,097

지난 시간에 스케줄러에 대해서 이야기했다. NT를 사용하거나 UNIX를 사용하거나 각각의 OS에는 스케줄러가 있다. 그리고 둘 다 라운드 로빈 방식에 의해서 스케줄링을 한다는 것만 기억하자. NT와 UNIX의 차이는 NT는 쓰레드로 스케줄링을 한다는 것이고 UNIX는 프로세스로 스케줄링을 한다는 것이다. NT는 하나의 프로세스에 여러 개의 쓰레드를 두어 처리하는 방법을 따르고 UNIX는 fork()와 같은 함수에 의해서 부모 프로세스를 복제하여 자식 프로세스를 만드는 것과 같이 여러 개의 자식 프로세스를 두어 처리하는 방법을 따른다. 예를 들어, 동시에 200개 이상의 작업을 처리한다고 할 때, NT에서는 200개의 쓰레드로 하지만 UNIX에서는 200개의 프로세스로 처리하기 때문에 NT에서 비교적 더 잘 처리할 수 있다. 그러나 NT에서도 동시에 많은 작업을 처리하는 데에는 쓰레드가 무겁기에 경량화(lightweight) 쓰레드를 소개했고, UNIX에서도 마찬가지로 경량화 프로세스, 즉 쓰레드를 제공하고 있다(아마도 웹과 같은 환경이 가장 큰 요인이겠지만). NT와 UNIX 모두 모든 것을 갖고 있는 종합 선물 세트 대신에 빠르게 처리할 수 있는 경량화된 쓰레드를 제공하고 있다. UNIX의 경량화 프로세스, 즉 쓰레드를 이용하게 된 것은 최근의 일이다. 시스템에 있는 프로세스의 확인은 NT는 시스템의 프로세스를 작업 관리자(Task Manager)를 통해서 할 수 있고, UNIX는 ps와 같은 명령으로 할 수 있다. GNU 유틸리티인 top을 이용할 수도 있다. 참고: NT 4.0에서 소개된 경량화 쓰레드인 fiber는 다소 다르다. 이 fiber는 프로그램내에서 수동으로 스케줄링된다. 이것은 Win16에서 자체적으로 쓰레드를 스케줄링하도록 작성된 응용 프로그램을 NT로 쉽게 포팅할 수 있도록 하기 위해 소개되었다. 물론 fiber는 생성한 쓰레드내에 있으므로 이 쓰레드의 스케줄링을 따른다. 쓰레드 프로그래밍 이점 쓰레드 프로그래밍이 갖고 있는 이점은 무엇일까? 먼저 프로세스는 전역 데이터, 환경 데이터, 힙, 쓰레드 스택, 쓰레드 코드로 이루어진다. 그림을 그려보면 다음과 같을 것이다.

두 개의 쓰레드를 갖고 있다면 다음 그림과 같이 될 것이다.

그림에서 알 수 있는 것처럼 쓰레드는 프로세스 내에 있는 데이터를 공유할 수 있다. 만약 프로세스간에 데이터를 주고 받으려면 IPC(Inter Process Communication)와 같은 복잡한 환경을 이용해야 한다. 기본적으로 프로세스간에 데이터를 주고 받는 것은 어렵다. 반면에 쓰레드간에 데이터를 주고 받는 것은 간단하다. 프로세서 친밀도 시스템에 있는 모든 프로세스는 프로세서 친밀도를 갖고 있다. 프로세서 친밀도는 프로세스가 어떤 CPU에서 실행될 것인지를 결정한다. 프로세서 친밀도는 NT와 UNIX 프로세스 모두 갖고 있다. 참고로 윈도우 2000부터는 하나의 프로세스에 있는 쓰레드에 대해서도 프로세서 친밀도를 지정할 수 있다. 또한 쓰레드 친밀도는 프로세스의 친밀도와 같은 값을 갖는다. 프로세서 친밀도는 멀티 프로세서를 갖고 있는 환경에서 시스템 부하가 많이 걸리는 작업을 특정 CPU에 나누어서 부하를 줄이고, 처리 시간을 줄이는 데 유용하게 사용될 수 있지만 사용할만한 확실한 이유가 없는 한 사용하지 않는 것이 좋다. 즉, 꼭 필요한 경우에만 사용하도록 한다. NT는 운영체제의 버전과 종류에 따라 사용할 수 있는 프로세서의 개수가 제한되어 있지만, 보통 8개의 CPU를 가진 환경에서 사용할 수 있는 값들은 다음과 같다.
Bit mask
Binary value
Eligible processors
0x0001
00000000 00000001
1
0x0003
00000000 00000011
1, 2
0x0007
00000000 00000111
1, 2, 3
0x0009
00000000 00001001
1, 4
0x007F
00000000 01111111
1, 2, 3, 4, 5, 6, 7
자신의 시스템이 몇 개의 CPU를 갖고 있는 가는 NT에서는 성능 뷰어나 작업 관리자에서 볼 수 있고, UNIX에서는 mpstat나 dmesg와 같은 명령으로 간단히 확인할 수 있다. C#에서 간단히 현재 실행중인 프로그램의 프로세서 친밀도를 알아내는 것은 다음과 같다. 대개의 경우 자신의 CPU가 1개일 것이므로 값은 1이 될 것이다. 그리고 여러 개의 CPU를 갖고 있다면 이 값을 변경하여 이 프로세스가 실행될 수 있는 CPU를 제한할 수 있을 것이다.
이름: ProcessApp.cs

using System;
using System.Diagnostics;
using System.ComponentModel;

class ProcessApp
{
  public static void Main()
  {
    Process proc = Process.GetCurrentProcess();

    try
    {
      //Process Name
      Console.WriteLine("Process Name: " + proc.ProcessName);
      //Processor Affinity
      Console.WriteLine("Processor Affinity: " + proc.ProcessorAffinity);
    }

    catch(Win32Exception e)
    {
      Console.WriteLine(e.ToString());
    }
  }
}
현재 실행중인 프로그램의 프로세스를 가져오기 위해 Process.GetCurrentProcess()를 사용하고 이것을 사용하기 위해서는 System.Diagnostics가 필요하다.
Process proc = Process.GetCurrentProcess();
NT에서 몇몇 시스템 서비스의 경우에는 프로세서 친밀도 값을 가져올 수 없다. 이러한 경우에 Win32Exception이 발생한다. 이 예외를 처리할 수 있도록 하기 위해 System.ComponentModel 네임 스페이스가 필요하다. 만약 현재 2개의 CPU를 갖고 있는 환경이라면 다음과 같이 프로세서 친밀도를 바꿀 수 있다.
  
proc.ProcessorAffinity = (IntPtr)3;
이 경우에는 두 개의 프로세서에서 모두 실행되도록 할 것이다. 단일 CPU 환경에서 이와 같이 한다면 에러를 만나게 될 것이다. IntPtr 데이터형은 시스템에 따른 고유한 정수 값 형식을 지정한다. Int형을 2 바이트로 쓴다면 2 바이트를 사용하고, 4 바이트를 사용하는 환경에서는 4 바이트를 사용하도록 하는 정수형이다. 다음은 시스템에 있는 모든 프로세스를 출력하는 예제다.
  
이름: pinfo.cs

using System;
using System.Diagnostics;

class pinfoApp
{
  public static void Main()
  {
    Process[] procs = Process.GetProcesses();

    foreach(Process proc in procs)
    {
      // Process Name
      Console.Write("Process Name: " + proc.ProcessName);
      // Process Id
      Console.WriteLine(", Process ID: " + proc.Id.ToString());
    }
  }
}
다음 단계 프로세서 친밀도에 대해서 알아보았다. 다음에는 쓰레드의 예외 처리에 대해서 알아보도록 하자.
TAG :
댓글 입력
자료실

최근 본 상품0