안녕하세요^^
오늘은 지난 시간에 예고한 대로 스레드(thread)에 대해서 알아보도록 하겠습니다.
먼저 thread가 뭔지 알아야 겠지요? thread는 process랑 비교하면서 보시면 조금 더 친근하게 다가 갈 수 있으리라 생각합니다^^
⊙ Thread : - thread는 process와 마찬가지로 CPU의 작업 단위 중 하나.
- But.! Process와는 달리 경량화된 Process(lightweight process)
<그림 1. thread>
- 위 그림처럼 thread는 thread식별자, 프로그램 카운터, 레지스터 집합, stack만을 갖으며,
process에서 보았던 text, data, 다른 OS자원은 process에 속한 다른 thread와 공유함.
thread는 위와 같이 자원을 공유하고 위와 같은 개념을 갖고 있다는 것을 일단 깔고 넘어가도록 하겠습니다.
그럼 이러한 thread를 왜 만들게 되었을 까요? 그 동기에 대해서 알아보겠습니다.
하나의 응용 프로그램에서 여러 가지 일을 동시에 수행할 수 있습니다. 이러한 일 처리를 위해서 자식 프로세스를 생성하여 처리할 수도 있지만, 자원의 공유와 비용의 문제가 있다는 것입니다. 그리하여 이 비용을 줄이고, 자원 공유를 쉽게 하기 위해서 thread라는 개념을 도입하였다고 합니다.
이제는 thread의 장점이 무엇인지 살펴 보겠습니다
- 응답성(responsiveness) : multithreaded 프로그램은 그것의 일부가 block되어도 나머지는 계속 실행 가능
- 자원공유(resource sharing) : 같은 process의 thread는 자원을 공유함
- 경제성(economy) : process마다 메모리와 자원을 할당하면 overhead가 발생하는데, thread를 사용하면 비용이 저렴해지고, context switch가 용이해짐.
이러한 장점들을 갖고 있습니다.
이젠 thread의 type에 대해서 알아보겠습니다.
크게 user thread와 kernel thread 가 있다고 보시면 되겠습니다. 즉, thread를 User mode에서도 Kernel mode에서도 구현이 가능하단 소리가 되겠지요. 그럼 각각에 대해서 간단하게 알아보겠습니다
- User thread : 사용자 공간에서 thread 라이브러리를 통해 제공
Kernel 지원 없이 thread 생성, 스케줄링, 관리를 제공
ex) POSIX > Pthread, Mach > C-thread, Solaris > UI-thread
- Kernel therad : OS가 직접 지원
Kernel이 thread 생성, 스케줄링, 관리 담당
Mode 변경이 필요하므로 상대적으로 느림.
ex) Windows NT, Windows2000/xp, Solaris2등
물론 위의 기능을 대부분의 OS가 두 가지 모두 제공을 합니다.
지금부터는 Multithreading Model을 알아 보도록 하겠습니다.
종류에는 다대일 모델(Many to one), 일대일 모델(one to one), 다대다 모델(Many to many), Two level 모델이 있습니다. 아래 그림과 하나씩 살펴보도록 하겠습니다.
<그림 2, Many-to-one Model>
여러 User thread가 하나의 Kernel thread로 mapping 되는 것을 말합니다. 그림만 딱 보셔도 어떤것인지 아시겠지요?^^ 이러한 모델의 장점은 thread 관리가 User mode에서 이루어지기 때문에 처리 속도가 빠르다는 것입니다. 단점이라 한다면, 하나의 thread가 block되면 전체의 process가 block 된다는 것입니다. 이러한 모델을 사용하는 것의 예는 Solaris의 Green Threads, GNU의 Portable Threads가 있습니다.
<그림 3, One-to-one Model>
이번에는 일대일 모델입니다. 말 그대로, 위 그림 그대로 입니다. 각 User thread가 하나의 Kernel thread에 mapping 됩니다. 장점은 하나의 thread가 block 되어도 나머지 thread는 동작이 가능하다는 것입니다. 단점은 비용이 비싸다는 것.. 그러므로 일반적으로는 thread의 수를 제한하고 있습니다. 예로는 Windows NT/XP/2000, Linux, Solaris9 and later 가 있습니다.
<그림 4, Many-to-many Model>
여러 User thread가 동일 수 또는 그 이하의 수의 Kernel thread에 mapping 됩니다. Kernel thread의 수는 응용 프로그램이나 기계의 특성에 따라 제한이 가능합니다. 장점은 비용이 일대일 모델보다 저렴하다는 것과 다대일 모델과 달리 스레드가 동시 수행이 가능하다는 것입니다. 예로는 Solaris prior to version 9, Windows NT/2000 with the ThreadFiber package 가 있습니다.
<그림 5, Two-level Model >
Many to Many Model과 비슷한 구조를 갖고 있습니다. 그 중에서도 중요하게 여겨지는 User thread에게 전용(?) Kernel thread를 제공해 주는 것 입니다. 장점이라 한다면 역시 위에서 언급했던 점유율이 높아야 하는 User thread에게 선점권을 부여할 수 있다는 것입니다. 예로는 IRIX, HP-UX, Tru64 UNIX, Solaris8 and earlier가 있습니다.
이런 thread를 사용하기 위한 Issue 또한 존재 할텐데요.. 어떤 것들이 있는지 알아보도록 하겠습니다.
바로 앞서 언급했던 System call 부분입니다. fork()와 exec()를 활용할 때, 조금 변경하여 사용하여야 하는데요. 이를 위해서 UNIX는 2가지 종류를 제시하고 있습니다. process 하나의 thread가 fork() 하면 process의 모든 thread가 복사된다는 것입니다. 다른 한 종류는 해당하는 하나의 thread만 복사되는 것. 이렇게 두 종류를 제공을 하고 있습니다. 이 두 종류 중 하나를 선택하는 것은 응용프로그램의 몫인데요. 만약 fork()된 후 바로 exec()를 호출 할 것 이라면, 모든 thread가 복사되는 첫 번째 방법은 자원 낭비가 될 것입니다.
위에서 이슈화 했던 것은 생성과 실행이고, 그럼 종료부분을 보겠습니다. 종료를 여기서는 thread cancellation이라고 칭하고 있습니다. 취소하는 형태에도 두 가지가 존재하는데요. 비동기식 취소(Asynchronous)와 지연된 취소(Deferred)가 있습니다. 비동기식은 목표 thread(target)가 바로 종료되나, 지연된 취소는 target thread가 바로 종료되지 않고 주기적으로 자신의 종료시점을 검사하여 적절한 시기에 종료되는 것을 말합니다.
이번에는 Signal Handling 에 대해서 알아보겠습니다.
UNIX에서는 signal을 이용하여 특정 사건이 일어났음을 Process에게 통보를 합니다. 이러한 신호는 Software Interrupt입니다. 이러한 신호는 동기식과 비동기식으로 수신이 됩니다. 동기식은 자신에 의해 생성된 신호이며, 비동기식은 외부에서 생성된 신호를 말합니다. 동기식 신호의 예로는 불법적인 메모리 접근을 들 수 있습니다. 신호 발생의 원인을 제공한 Process에게 신호가 전달 됩니다. 비동기식 신호는 Ctrl + C 처럼 신호가 수행중인 Process의 외부적 요인에 의해 발생한 경우 입니다.
신호처리 과정은 다음과 같습니다.
- 특정 event의 발생에 신호가 생성
- 생성된 신호는 process에 전달
- 신호의 처리
이러한 신호를 처리해주는 signal handler도 있을 것입니다. 두 가지 종류가 있습니다.
- default signal handler : 모든 신호마다 그것을 처리하는 default signal handler가 존재 함.
Kernel이 수행
- User defined handler : User가 signal handler를 정의하면 우선적으로 해당 handler가 처리
아까 위에서 언급했던 내용 중에 thread 수를 관리 한다는 말을 살짝 언급한 적이 있습니다. 이러한 부분도 Issue가 존재하겠지요. 바로 process가 생성할 수 있는 thread의 수를 적절하기 관리하기 위해 thread pool을 활용합니다. thread를 필요할 때 마다 생성하지 않고 Process가 생성 시에 적정한 수의 thread를 생성하여 thread pool에 대기하도록 하는 것입니다. thread가 필요할 시 thread pool에서 하나를 활성화 하여 사용합니다. 장점은 보다 빠르게 처리할 수 있다는 점, thread의 수를 제한할 수 있는 효과적인 방법이라 볼 수 있다는 점입니다.
여기까지 thread에 대해서 알아 보았습니다. Process랑은 또 살짝 다른 그런 모습입니다. 그러면서도 닮아 있는 녀석이 thread라는 생각이 드네요.
우리가 많이 사용하는 Windows XP threads에 대해서 살펴 보고 이번 포스팅을 마무리 할까 합니다.^^
Windows XP는 앞서 예시에서도 보았듯이 one-to-one Model을 활용하므로 Kernel과는 일대일 mapping 됩니다. 각 thread에는 아래와 같은 내용을 포함합니다.
- A thread ID
- Register set
- Separate user and Kernel stacks
- Private data storage area
thread에 포함된 data structure 에는 ETHREAD(executive thread block), KTHREAD(kernel thread block), TEB(thread environment block)가 있습니다.
<그림 6, Windows XP threads>
위와 같은 구조로 동작합니다^^ 이렇게 간단하게 우리가 주로 사용하는 OS인 Windows XP의 threads를 살펴 보았습니다.
허접한 정리이지만^^;; 끝까지 봐 주신 여러분께 감사드립니다^^
본 포스팅의 저작권은 보안인닷컴과 작성자에 있으며 상업적 이용을 배제하며 콘텐츠 이용시에는 반드시 출처와 링크를 이용해 주시기 바랍니다. 무단도용은 저작권법에 저촉을 받습니다..
****************************************************************************************************