운영체제 - 쓰레드란?(Thread,사용자 수준 쓰레드, 커널 수준 쓰레드, 혼합형 쓰레드)

2019. 7. 27. 22:29인프라/운영체제

2019/07/27 - [운영체제] - 운영체제 - 프로세스(Process)란? 프로세스상태,Context Switching

 

운영체제 - 프로세스(Process)란? 프로세스상태,Context Switching

프로세스의 개념 프로세스는 다양한 정의가 있다. 실행 중인 프로그램 비동기적 행위 실행 중인 프로시저 실행 중인 프로시저의 제어 추적 운영체제에 들어 있는 프로세스 제어 블록(PCB) 프로세서에 할당하여 실..

coding-start.tistory.com

 

쓰레드(Thread)란 간단히 말해 프로세스 내에서 실행되는 실행 단위이다. 프로세스는 이러한 쓰레드를 한 개 이상으로 나눌 수 있다. 쓰레드는 프로그램 카운터와 스택 포인터 등을 비롯한 쓰레드 실행 환경 정보(Context 정보), 지역 데이터, 스택을 독립적으로 가지면서 코드, 전역 데이터, 힙을 다른 쓰레드와 공유한다.

그림을 보면 프로세스 내에서 쓰레드는 별도의 Stack(+ 스레드 실행 환경 정보, 지역데이터, 레지스터 등)을 할당받고 Code, Data, Heap 영역은 같은 프로세스 내의 다른 쓰레드와 공유한다.

 

프로세스 하나에 포함된 쓰레드들은 공동의 목적을 달성하려고 병렬로 수행한다. 이러한 쓰레드를 이용하면 아래와 같은 이점들이 있다.

  • 사용자 응답성 증가
  • 프로세스 자원과 메모리 공유가능
  • 경제성이 좋음(프로세스 컨텍스트 스위칭보다 쓰레드 컨텍스트 스위칭이 오버헤드가 더 적다.)
  • 다중 처리로 성능과 효율 향상

현대 시스템은 대부분 다중 쓰레드 운영체제이다. 다중 쓰레드는 프로그램 하나를 여러 실행 단위로 쪼개어 실행한다는 측면에서 다중 처리(다중 프로세싱)와 의미가 비슷하다. 하지만 동일 프로세스의 쓰레드는 자원을 공유하므로 자원 생성과 관리의 중복성을 최소화하여 실행 능력을 향상시킬 수 있다. 그리고 각 쓰레드는 커널이 개입하지 않고도 독립적으로 실행할 수 있어 서버에서 많은 요청을 효과적으로 처리할 수 있다.

 

이러한 쓰레드의 특성 때문에 프로세스보다 쓰레드를 생성하는 것이 더 빠르고, 동일한 프로세스에 있는 쓰레드 간의 교환이나 쓰레드 종료도 훨씬 빠르다.

 

보통 프로세스를 생성하면 해당 프로세스의 쓰레드도 함께 생성한다. 단, 쓰레드 생성에서는 운영체제가 부모 프로세스와 공유할 자원을 초기화할 필요가 없다. 해당 프로세스가 스택과 레지스터를 직접 제공하기 때문이다. 그러므로 프로세스의 생성과 종료보다는 오버헤드가 훨씬 적다. 여기서 스레드의 장점 하나는 쓰레드 한개가 대기 상태로 변할 때 전체 프로세스를 대기 상태로 바꾸지 않는다는 것이다. 실행 상태의 쓰레드가 대기 상태가 되면 다른 쓰레드를 실행할 수 있다. 그러나 프로세스와 달리 서로 독립적이지는 않다. 프로세스 하나에 있는 전체 쓰레드는 프로세스의 모든 주소에 접근할 수 있으므로 쓰레드 한 개가 다른 쓰레드의 스택을 읽거나 덮어쓸 수 있다.

 

쓰레드 제어 블록(TCB)

프로세스가 프로세스 제어 블록에 정보를 저장하듯이 쓰레드도 쓰레드 제어 블록에 정보를 저장한다. 그런데 프로세스는 쓰레드를 한 개 이상 가질수 있으므로, 결국 프로세스 제어블록은 스레드 제어 블록의 리스트를 가리킨다.

 

쓰레드의 구현

쓰레드는 운영체제에 따라 다양하게 구현할 수 있는데, 대부분 다음 세 가지 형태로 구현한다. 사용자 수준 쓰레드는 쓰레드 라이브러리를 이용하여 작동하는 형태이고, 커널 수준 쓰레드는 커널(운영체제)에서 지원하는 형태이다. 그리고 이 둘을 혼합한 형태가 혼합형 쓰레드이다.

 

  1. 사용자 수준 쓰레드 - 다대일 매핑
  2. 커널 수준 쓰레드 - 일대일 매핑
  3. 혼합형 쓰레드 - 다대다 매핑

 

<사용자 수준 쓰레드>

사용자 수준 쓰레드는 사용자 영역의 쓰레드 라이브러리로 구현하고, 쓰레드와 관련된 모든 행위를 사용자 영역에서 하므로 커널이 쓰레드의 존재를 알지 못한다. 여기서 쓰레드 라이브러리는 쓰레드의 생성과 종료, 쓰레드 간의 메시지 전달, 쓰레드의 스케줄링과 컨텍스트 등 정보를 보관한다. 

사용자 수준 쓰레드에서는 쓰레드 교환에 커널이 개입하지 않아 커널에서 사용자 영역으로 전환할 필요가 없다. 그리고 커널은 쓰레드가 아닌 프로세스를 한 단위로 인식하고 프로세서를 할당한다. 다수의 사용자 수준 쓰레드가 커널 수준 쓰레드 한 개에 매핑되므로 다대일 쓰레드 매핑이라고 한다. 

 

 

사용자 수준 쓰레드의 장점

  • 이식성이 높음 : 커널에 독립적으로 스케쥴링을 할 수 있어 모든 운영체제에 적용할 수 있다.
  • 오버헤드가 적음 : 스케쥴링이나 동기화를 하려고 커널을 호출하지 않으므로 커널 영역으로 전환하는 오버헤드가 줄어든다.
  • 유연한 스케쥴링이 가능 : 커널이 아닌 쓰레드 라이브러리에서 쓰레드 스케줄링을 제어하므로 응용 프로그램에 맞게 스케줄링할 수 있다.

사용자 수준 쓰레드의 단점

  • 시스템의 동시성을 지원하지 않음 : 쓰레드가 아닌 프로세스 단위로 프로세서를 할당하여 다중 처리 환경을 갖춰도 쓰레드 단위로 다중 처리를 하지 못한다. 동일한 프로세스의 쓰레드 한개가 대기 상태가 되면 이 중 어떤 쓰레드도 실행하지 못한다.
  • 확장에 제약이 따름 : 커널이 한 프로세스에 속한 여러 쓰레드에 프로세서를 동시에 할당할 수 없어 다중 처리 시스템에서 규모를 확장하기가 어렵다.
  • 쓰레드 간 보호 불가능 : 쓰레드 간 보호에 커널의 보호 방법을 사용할 수 없다. 쓰레드 라이브러리에서 쓰레드 간 보호를 제공해야 프로세스 수준에서 보호가 가능하다.

 

<커널 수준 쓰레드>

커널 수준 쓰레드는 사용자 수준 쓰레드의 한계를 극복하는 방법으로, 커널이 쓰레드와 관련된 모든 작업을 관리한다. 한 프로세스에서 다수의 쓰레드가 프로세서를 할당받아 병행으로 수행하고, 쓰레드 한 개가 대기 상태가 되면 동일한 프로세스에 속한 다른 쓰레드로 교환이 가능하다. 이때도 커널이 개입하므로 사용자 영역에서 커널 영역으로 전환이 필요하다. 커널 수준 쓰레드는 사용자 수준 쓰레드와 커널 수준 쓰레드가 일대일로 매핑된다. 따라서 사용자 수준 쓰레드를 생성하면 이에 대응하는 커널 쓰레드를 자동으로 생성한다.

 

커널 수준 쓰레드는 커널이 직접 스케줄링하고 실행하기에 사용자 수준 쓰레드의 커널 지원이 부족한 문제를 해결할 수 있지만, 커널이 전체 프로세스와 쓰레드 정보를 유지하여 오버헤드가 커진다. 대신 커널이 각 쓰레드를 개별적으로 관리할 수 있어 동일한 프로세스의 쓰레드들을 병행으로 수행할 수 있다. 동일한 프로세스에 있는 쓰레드 중 한 개가 대기 상태가 되더라도 다른 쓰레드를 실행할 수 있다는 장점이 있다. 하지만 이 과정에서도 커널 영역으로 전환하는 오버헤드가 발생하고 스케쥴링과 동기화를 하려면 더 많은 자원이 필요하다.

 

<혼합형 쓰레드>

혼합형 쓰레드는 사용자 수준 쓰레드와 커널 수준 쓰레드를 혼합한 구조이다. 이는 시스템 호출을 할 때 다른 쓰레드를 중단하는 다대일 매핑의 사용자 수준 쓰레드와 쓰레드 수를 제한하는 일대일 매핑의 커널 수준 쓰레드 문제를 극복하는 방법이다. 즉, 사용자 수준 쓰레드는 커널 수준 쓰레드와 비슷한 경량 프로세스에 다대다로 매핑되고, 경량 프로세스는 커널 수준 쓰레드와 일대일로 매핑된다. 결국 다수의 사용자 수준 쓰레드에 다수의 커널 쓰레드가 다대다로 매핑된다. 

 

 

프로세스 하나에는 경량 프로세스가 하나 이상 있고, 경량 프로세스에는 이에 대응하는 커널 쓰레드가 한 개 있다. 그리고 자원과 입출력 대기를 하려고 경량 프로세스 단위로 대기하므로 프로세스는 입출력을 완료할 때까지 대기할 필요가 없다.(다른 경량 프로세스는 대기상태가 아니기 때문) 어떤 경량 프로세스가 입출력 완료를 기다리더라도 동일한 프로세스에서 다른 경량 프로세스를 실행할 수 있기 때문이다.

 

[쓰레드 풀링]

시스템이 관리하는 쓰레드의 풀을 응용 프로그램에 제공하여 스레드를 효율적으로 사용할 수 있게 하는 방법이다. 즉, 미리 생성한 스레드를 재사용하도록 하여 스레드를 생성하는 시간을 줄여 시스템의 부담을 덜어준다. 또 동시에 생성할 수 있는 스레드수를 제한하여 시스템의 자원 소비를 줄여서 응용 프로그램의 전체 성능을 일정 수준으로 유지한다.