눈팅하는 게임개발자 블로그
Thread 본문
Thread 개념이 나타난 배경
프로세스가 작업 단위로서 사용 되기에 여러 단점들이 존재함.
- 프로세스 생성에 드는 비용이 크다.
프로세스를 위한 메모리를 할당하고, PCB(Process Control Block)를 생성하고, 페이지 테이블 생성하는 등
프로세스를 생성하는 시간의 오버헤드가 크다.
- 프로세스 컨텍스트 스위칭에 드는 비용이 크다.
CPU와 PCB 사이의 컨텍스트 교환에 드는 비용이 크고.
페이지 테이블 전환(TLB 등)에 따른 지연 시간이 길고, CPU 캐시 변경 등에 드는 비용이 크다.
- 프로세스 사이 통신의 어려움
프로세스들은 완전히 독립적인 주소 공간을 가지고 있기 때문에
두 프로세스 사이에 데이터를 주고 받기 위해서는 제 3의 공간이나 특별한 방법이 필요.
IPC를 이용할 경우 커널의 도움이 필요하여 소모 시간이 크다.
이외로도 코딩 난이도가 높고, 실행 속도가 느리고, 운영체제 호환성 부족 등의 단점이 있다.
스레드는 위의 프로세스의 문제점들을 해결하기 위해 고안되었다.
프로세스보다 더 작은 작업 단위(운영체제의 스케줄링 단위)로 사용되며
프로세스 생성 및 소멸에 따른 비용을 감소시키고 컨텍스트 스위칭의 소모 시간을 감소시키며
프로세스의 복잡한 통신 방법, 느린 실행 속도, 높은 코딩 난이도와 같은 문제를 해소한다.
Thread 개념
프로세스는 스레드들의 컨테이너가 되며
같은 프로세스 내의 스레드들에게 공유 환경을 제공한다.(프로세스 메모리 공간 등)
스레드는 프로세스 내에서 함수 단위로 작성되며 작업 실행 단위가 되어 운영체제의 관리를 받는다.
운영체제는 TCB(Thread Control Block, 스레드에 대한 정보를 저장하는 구조체) 리스트로 스레드를 관리하고
스레드를 단위로 스케줄링을 한다.
한 프로세스 내의 모든 스레드가 종료되면 해당 프로세스가 종료된다.
Thread 주소 공간
하나의 스레드가 실행되기 위해 주어지는 주소 공간은 6개의 영역으로 나누어진다.
1. Thread Code : 스레드의 코드가 저장된 공간
2. TLS(Thread Local Storage) : TLB에 위치하며 다른 스레드와 공유하지 않는 해당 스레드만이 사용하는 영역
3. Thread Stack : 스레드에 사용되는 지역 변수, 매개 변수가 저장되는 공간
4. 프로세스의 전역 변수 공간 : 프로세스 내부에 존재하는 모든 스레드가 접근 가능한 전역 변수가 담긴 공간.
5. 프로세스의 힙 메모리 공간 : 모든 스레드가 사용 가능한 프로세스의 힙 메모리 영역.
6. 커널 스택 : 해당 스레드가 커널 모드에서 실행될 때 사용되는 커널 공간.
커널 레벨 스레드와 사용자 레벨 스레드
스케줄링을 행하는 주체가 누군가에 따라 2 종류의 스레드로 구분된다.
커널 레벨 스레드 : 커널에 의해 직접 스케줄링되는 스레드.
유저 레벨 스레드 : 스레드 라이브러리에 의해 스케줄링되는 스레드.
커널 레벨 스레드
커널이 스레드에 대한 정보를 커널 공간에 생성하고 소유한다.
커널에 의해 스케줄되며 스레드 주소 공간이 사용자 공간, 커널 공간 구분없이 존재 가능하다.
응용 프로그램이 시스템 호출을 통해 커널 레벨 스레드를 생성할 경우 스레드 주소 공간은 사용자 주소 공간에 형성.
커널 코드에서 시스템 호출을 통해 커널 레벨 스레드를 생성할 경우 스레드 주소 공간은 커널 공간에 형성.
사용자 레벨 스레드
스레드 라이브러리가 스레드에 관한 정보(U-TCB)를 사용자 공간에 생성하고 소유.
스레드 라이브러리에 의해 스케줄되며 커널은 사용자 레벨 스레드의 존재를 모른다.
멀티 스레드 구현
멀티 스레드 구현 시 사용자 레벨 스레드와 커널 레벨 스레드를 매핑하는 방법.
N:1 매핑(사용자 레벨 N개에 커널 레벨 1개 매핑)
운영체제가 모든 프로세스를 단일 스레드 프로세스 처럼 사용한다.
프로세스당 1개의 커널 레벨 스레드(TCB) 생성.
단일 코어 CPU에서의 속도가 빠르지만 멀티 코어 CPU가 대부분인 현대 컴퓨터에서 비효율적이다.
1:1 매핑(사용자레벨 1개에 커널 레벨 1개 매핑)
사용자 스레드 하나마다 커널 레벨 스레드 하나씩 매칭.
이를 위해 응용 프로그램에 커널 레벨 스레드를 만들어 주기 위한 시스템 콜이 필요하다.
사용자 레벨 스레드는 매핑된 커널 레벨 스레드가 스케줄되면 실행된다.
개념이 단순하여 구현이 용이하고 병렬성이 높지만 커널에게는 부담이 크다.
사용자 레벨 스레드가 많아지면 그만큼 커널 레벨 스레드가 많아지므로 모든 것이 커널의 부담이 된다.
N:M 매핑(사용자레벨 N개에 커널 레벨 M개 매핑)
1:1 매핑에 비해 커널 레벨 스레드의 개수가 작아서 커널의 부담이 적지만
구현이 복잡해서 잘 사용되지 않는 방법.