CLR 쓰레드와 OS 쓰레드의 관계에 대하여...

[제목] CLR 쓰레드와 OS 쓰레드의 관계에 대하여...

CLR 쓰레드는 어떻게 OS 쓰레드와 다른가? CLR 쓰레드와 OS 쓰레드의 관계를 살피는 것은 CLR에서의 멀티 쓰레딩 환경을 개념적으로 이해하는데 도움이 된다.

윈도우 OS에서 하나의 프로세스는 하나 이상의 쓰레드를 가지며, 하나의 쓰레드는 2개의 스택을 갖는다. OS 쓰레드는 유저모드에 사용하는 스택과 그 쓰레드가 Kernel 로 들어 갔을 때 사용하는 별도의 Kernel 스택을 갖고 있다. 쓰레드 스택은 디폴트로 1M의 스택사이즈를 갖는데, 필요한 경우 개발자가 늘릴 수 있다. 만약 어떤 이유에서 이 스택 사이즈를 초과하게 되면, Stack Overflow 에러가 발생하게 된다. 예를 들어, 흔히 Recurisve 호출을 잘못하는 경우 Call Stack이 계속 증가하여 스택 사이즈를 초과할 수 있다.

OS 쓰레드와 CLR 쓰레드는 개발자의 입장에서 거의 비슷하면서도 다른 점을 갖고 있다. 만약 완전히 같다면, 굳이 다르게 이름 붙일 필요가 없었을 것이다. CLR 쓰레드는 .NET Framework의 System.Threading.Thead로 표현되는데, 기존의 OS 쓰레드에는 존재하지 않는 CLR이 필요로하는 추가 정보들을 갖고 있다. CLR은 CLR 쓰레드가 어떤 Managed Heap 객체를 접근하고 있는지등의 정보를 비롯하여 CLR의 보안(Security), 실행 Context 등 CLR 쓰레드 고유의 정보를 Track하게 된다. 이렇게 별도의 CLR 쓰레드를 만들게 됨으로서 이루어져야 하는 OS 쓰레드에서 CLR 쓰레드로의 전환, 혹은 그 반대로의 전환은 CLR이 자동으로 처리해 준다.

.NET Applicaiton 프로세스는 메인쓰레드와 Finalizer 쓰레드 등 최소 2개의 CLR 쓰레드를 비롯하여 복수의 쓰레드들을 갖는다. .NET 프로그램을 실행한 후 Windbg 같은 Debugger로 살펴 보면, Managed Thread와 Native Thread를 자세히 살펴 볼수 있다. 예를 들어, 아주 간단한 WinForm 프로그램을 만들어 Windbg로 살펴보면, 아래 예에서는 Native OS 쓰레드는 7개가 있음을 알 수 있다. (주: Windbg에서 ~ 명령은 모든 쓰레드를 표시하라는 명령이다)

0:006> ~
   0  Id: 1770.1498 Suspend: 1 Teb: 7f3ab000 Unfrozen
   1  Id: 1770.d34 Suspend: 1 Teb: 7f3a8000 Unfrozen
   2  Id: 1770.101c Suspend: 1 Teb: 7f3a5000 Unfrozen
   3  Id: 1770.6ac Suspend: 1 Teb: 7f27f000 Unfrozen
   4  Id: 1770.15fc Suspend: 1 Teb: 7f27c000 Unfrozen
   5  Id: 1770.2750 Suspend: 1 Teb: 7f279000 Unfrozen
.  6  Id: 1770.206c Suspend: 1 Teb: 7f276000 Unfrozen

0:006> .load sos
0:006> !threads
ThreadCount:      2
UnstartedThread:  0
BackgroundThread: 1
PendingThread:    0
DeadThread:       0
Hosted Runtime:   no
                                                                         Lock  
       ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
   0    1 1498 01119420     26020 Preemptive  02C7E64C:00000000 010e1480 0     STA 
   2    2 101c 010e90a0     2b220 Preemptive  00000000:00000000 010e1480 0     MTA (Finalizer) 

그리고, Managed CLR 쓰레드를 살펴보기 위해, !thread 명령 결과를 보면 2개만이 CLR 쓰레드임을 알 수 있다 (주: .Windbg에서 .NET 프로그램을 디버깅하기 위해서는 보통 SOS (sos.dll)라는 Debugger extension을 사용한다. 이 SOS의 threads 명령은 CLR 쓰레드를 출력해 준다). !threads 출력을 자세히 보면, 각 CLR 쓰레드는 OSID 즉 OS 쓰레드 ID 와 연결되어 있음을 알 수 있다. 즉, 모든 OS 쓰레드가 CLR 쓰레드는 아니지만, 모든 CLR 쓰레드는 실제 작업을 위해 OS Thread를 사용하게 된다.

그렇다면 하나의 CLR 쓰레드에는 반드시 동일한 하나의 OS 쓰레드가 매핑되는가? 즉 위의 예에서 Managed ThreadID가 1인 경우 항상 고정된 OSID 1498 이 작업하게 되는가? CLR은 이러한 매핑 관계를 보장하지 않는다. 즉, (실무적으로 극히 드물지만) 이론적으로 하나의 CLR 쓰레드에 다른 OS 쓰레드가 매핑될 수 있다.

더 나아가 만약 .NET Application이 ASP.NET처럼 복수의 AppDomain을 갖는다면 (주: ASP.NET은 하나의 Web Application 당 하나의 AppDomain을 갖는다), 하나의 OS 쓰레드는 여러 AppDomain의 쓰레드들에 공유되어 사용되어 질 수 있다. 만약 3개의 AppDomain 이 있다고 가정하고, 각 AppDomain당 4개의 쓰레드가 존재한다고 가정했을 때, 이론적으로 4개의 OS 쓰레드가 3개의 AppDomain에 공유되어 사용되어 질 수 있다 (물론 더 많은 OS 쓰레드 사용 가능). 한 AppDomain에 4개의 쓰레드가 있다면, 4개의 OS 쓰레드가 사용되어 진다. 한 AppDomain의 복수 CLR 쓰레드에 하나의 OS 쓰레드가 할당되어 질 수는 없다.



본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.