Part 02. 프로세스와 스레드
프로세스, 스레드(2)
프로세스에서 실행 제어만 분리한 실행 단위
스레드를 하나만 가진 작업을 중량 프로세스(HWP)라 부른다. 여기서 **경량 프로세스(LWP)**는 프로세서를 사용하는 기본 단위로, 명령어를 독립적으로 실행할 수 있는 하나의 제어 흐름을 뜻한다. 이런 스레드들이 모인 그룹 환경을 작업이라 하며, 같은 그룹에 속한 스레드들은 코드, 주소 공간, 파일이나 신호 같은 운영체제 자원을 함께 공유한다.
작업에 스레드가 하나도 없으면 아무 일도 할 수 없으므로, 작업은 반드시 스레드를 가져야 한다.
프로세스와 스레드의 구성
프로세스는 스레드를 하나 이상 가지며, 각 스레드는 다음 정보를 담고 있다: 스레드의 실행 상태(실행, 준비), 실행 스택, 지역 변수와 스레드별 데이터를 저장하는 스레드별 정적 저장소, 그리고 프로세스의 다른 스레드가 공유하는 메모리와 자원에 대한 접근 정보를 포함한 실행 환경(문맥) 정보다.
스레드의 장점
프로세스에 속한 스레드들은 공통의 목적을 이루기 위해 병렬로 수행된다. 덕분에 하나의 프로세스가 서로 다른 프로세서에서 프로그램의 다른 부분을 동시에 실행할 수 있어, 시스템 성능과 효율이 향상된다.
운영체제는 단일 프로세스 안에서 단일 스레드 실행과 다중 스레드 실행을 모두 지원한다. 단일 스레드 프로세스는 프로세스 하나에 스레드 하나가 실행되는 전통적인 방식(MS-DOS가 대표적이다)이고, 다중 스레드 프로세스는 프로세스 하나에서 여러 스레드가 함께 실행되는 방식(Windows NT/XP, Solaris 등)이다.
다중 스레드의 특징
각 스레드를 별도의 프로세서에서 실행한다는 측면에서는 다중 프로세싱과 비슷한 의미를 갖는다. 다만 같은 프로세스 안의 스레드들은 메모리와 파일을 공유하므로, 프로세스 하나가 여러 실행 단위로 나뉘어 자원을 함께 쓰는 셈이다. 이 덕분에 자원을 생성하고 관리하는 데 드는 중복을 최소화해 실행 능력이 향상되고, 서버가 많은 요청을 효과적으로 처리할 수 있는 환경도 마련된다.
단일 스레드 프로세스 모델은 프로세스를 하나의 스레드와, 그 스레드가 가진 레지스터·스택으로 표현한다. 다중 스레드 프로세스 모델은 프로세스를 각각의 스레드와 고유의 레지스터·스택으로 표현하되, 프로세스의 주소 영역은 모든 스레드가 함께 공유한다.
단일 사용자 다중 처리 시스템 환경
이 환경에서는 시스템 호출이 아니라 사용자 라이브러리 수준에서 스레드 개념을 제공하므로 속도가 빠르고, 프로그램에 비동기적 요소를 구현할 수 있다. 실행 중인 스레드를 대기 상태로 바꾸고 다른 스레드로 제어를 옮기는 이러한 상태 전환은, 서버 하나가 많은 요청을 효과적으로 받아 처리하는 방법이 된다.
공유 메모리 형태의 다중 프로세서 시스템 환경
이 환경에서는 프로그램을 공유 메모리에 저장하고 각 스레드를 프로세서에 할당해 병렬로 처리함으로써, 프로세서 성능을 크게 끌어올릴 수 있다.
스레드의 단점
사용자 수준 스레드에서는 커널 자체가 스레드 하나로 구성되어 있어, 시스템 호출을 실행하면 그 스레드가 속한 전체 작업이 시스템 호출의 결과가 돌아올 때까지 함께 대기해야 한다.
스레드의 특징
스레드는 준비, 실행, 대기, 종료 상태로 구분되며, 프로세서를 함께 쓰지만 항상 하나의 스레드만 실행된다. 한 프로세스에 속한 스레드들은 순차적으로 실행되고, 각자 자신만의 프로그램 카운터와 스택을 가진다. 스레드를 생성할 때 운영체제는 부모 프로세스와 공유할 자원을 따로 초기화하지 않는다. 프로세스 내부의 스레드는 같은 프로세스에서 다른 스레드를 만들 수 있는데, 새로 만들어지는 스레드에는 스택과 레지스터만 마련해주면 되므로 프로세스를 생성하고 종료하는 것보다 오버헤드가 훨씬 적다. 스레드 하나가 대기 상태로 바뀌어도 전체 프로세스가 함께 대기 상태가 되지는 않는다. 다만 스레드들은 서로 완전히 독립적이지 않아서, 한 작업 안의 스레드는 그 작업의 모든 주소에 접근할 수 있다. 결국 스레드는 한 명의 사용자가 소유한, 여러 스레드를 가진 작업 하나에 속하는 셈이다.
스레드 구현 수준
스레드는 운영체제에 따라 사용자 수준, 커널 수준, 혹은 이 둘을 혼합한 방식 중 하나로 구현된다. Windows 2000/XP, Mach, OS/2, Solaris 같은 운영체제는 커널 수준에서 스레드를 지원하며 시스템 호출을 제공하고, 사용자 수준에서는 라이브러리 호출을 통해서도 스레드를 지원할 수 있다.
사용자 수준 스레드
사용자 수준 스레드는 커널 스레드를 지원하지 않는 운영체제에서 주로 쓰인다. 여러 개의 사용자 수준 스레드가 커널 스레드(프로세스) 하나에 매핑되는 방식으로, 다중 스레드 프로세스에 실행 문맥 하나만 할당한다는 뜻에서 M:1 스레드 매핑이라 부른다. 스레드 관리가 사용자 수준(공간)에서 효율적으로 이루어지므로, 스레드와 관련된 모든 과정을 응용 프로그램이 직접 수행한다. 응용 프로그램은 사용자 수준 스레드 관리 루틴들로 구성된 스레드 라이브러리(스레드 패키지)를 이용해 다중 스레드로 프로그래밍할 수 있으며, 처음에는 스레드 하나로 시작해 그 스레드에서 실행을 시작한다.
이 방식은 몇 가지 뚜렷한 장점이 있다. 커널을 수정하지 않고도 어떤 운영체제에나 적용할 수 있는 높은 이식성을 갖고, 스레드 관리를 위한 데이터 구조가 모두 프로세스의 사용자 주소 공간 안에 있어 커널의 도움 없이 스레드를 교체할 수 있으므로 오버헤드가 줄어들며, 스레드 라이브러리가 스케줄링을 직접 제어하므로 응용 프로그램에 맞게 유연하게 스케줄링할 수 있다.
반면 단점도 있다. 한 번에 하나의 스레드만 커널에 접근할 수 있어 여러 스레드가 시스템 호출을 동시에 사용할 수 없으므로 시스템의 동시성을 지원하지 못하고, 커널이 프로세스 내부의 다중 스레드를 프로세스 하나로만 관리하기 때문에 다중 처리 환경에서 여러 프로세스를 이용한 분산 처리가 불가능해 규모 확장에 제약이 있으며, 스레드 간 보호에 커널의 보호 기법을 쓸 수 없어 스레드 라이브러리가 직접 보호 기능을 제공해야 하는 만큼 스레드 간 보호가 어렵다.
병렬 실행
하나의 스레드가 시스템 호출을 하면 다른 스레드가 함께 멈춰버리는 M:1 방식의 문제는, 다중 프로세서에서 다중 스레드를 병렬로 실행함으로써 해결할 수 있다. 이렇게 하면 시스템 규모를 확장하기 쉬워지고 처리량도 늘어난다.
이식성
시스템이 바뀌면 제공되는 스레드 API를 이용해 프로그램을 수정한다. 다만 자원이 제한되어 있는 만큼, 사용자 수준 스레드를 만든다고 해서 커널 스레드를 무한정 생성할 수는 없다.


