프로세스, 쓰레드가 뭔가요?
프로세스: 프로세스는 실행 중인 프로그램의 인스턴스로, 독립적인 메모리 공간(가상 메모리)와 자원(파일 핸들, 네트워크 연결 등)을 가진다. OS가 프로세스의 생성 및 관리를 맡는다.
쓰레드: 쓰레드는 프로세스 내의 실행 흐름 단위로, 상위 프로세스의 자원과 메모리(코드, 데이터, 힙)를 공유한다. 각 쓰레드는 독립적인 스택 공간을 가지며, 멀티쓰레딩을 통해 프로세스 내에서 여러 작업을 동시에 수행할 수 있다.
프로세스(Process)
프로세스는 실행 중인 프로그램의 인스턴스라는 말은 다음과 같이 비유할 수 있다.
- 보조기억장치의 프로그램 실행 파일 = 설계도
- 보조기억장치의 실행 파일은 프로그램의 코드와 데이터를 포함하고 있다. 이 파일은 프로그램이 어떻게 동작해야 하는지에 대한 정보(즉, 설계도)를 담고 있다.
- 프로세스 = 생성된 물건
- 메인 메모리에 로드되고 실행 중인 프로그램을 프로세스라고 한다. 이는 실행 파일(설계도)이 실제로 실행되어 작업을 수행하는 '실체'(생성된 물건)로 변환된 상태이다.
- 프로그램과 달리 실체이기 때문에, 자원을 소모한다. 따라서 필요한 메모리, CPU 시간, 입출력 자원 등을 할당받는다.
이 비유를 통해, 실행 파일이 단순히 정적인 코드와 데이터의 집합일 뿐이며, 프로세스는 이를 실제로 실행하는 동적인 Entity임을 이해할 수 있다. 프로세스는 프로그램이 '살아있는' 상태로, 실제로 시스템 자원을 사용하며 작업을 수행하는 단계를 의미한다.
프로세스의 생성
그럼 '어떻게 디스크의 실행 파일이 살아있는 프로세스가 되는 건데?' 라는, 그 과정에 대한 궁금증이 생긴다.
그 과정을 단계별로 살펴보면 다음과 같다.
- 프로그램이 실행되기 전에는 보조기억장치(하드 드라이브, SSD 등)에 실행 파일 형태로 저장되어 있다.
- 프로그램을 실행하면, 운영체제는 실행 파일을 메인 메모리로 로드한다. 그 과정은 다음과 같다.
- 사용자 또는 다른 프로그램이 특정 프로그램을 실행하도록 요청
- 운영체제는 보조기억장치에서 요청받은 프로그램의 실행 파일(예: .exe 파일)을 찾는다.
- 운영체제는 새로운 프로세스를 생성한다. 이 과정에서 프로세스 식별자(Process ID, PID)가 할당되며, 프로세스의 기본 구조가 메모리에 설정된다.
- 프로세스에 메모리 자원을 할당한다. 이 때 가상 메모리 관리 시스템이 사용된다. 코드, 데이터, 힙, 스택 등의 세그먼트가 가상 주소 공간 내에 배치된다.
- 실행 파일의 내용을 파싱하여, 기계어 코드와 데이터를 메모리에 로드한다.
- 보조기억장치의 ELF 파일에서 코드(.text)와 데이터(.data) 세그먼트의 내용을 파싱하고 메모리의 해당 영역으로 복사한다. 이 과정에서 파일의 바이너리 내용이 메모리에 로드된다.
- 동시에, 커널에 의해 코드 세그먼트는 실행 가능하도록 설정되며, 데이터 세그먼트는 읽기/쓰기 가능하도록 설정된다.
- 이는 주로 보조기억장치 I/O 작업을 통해 수행된다.
(그러나 커널에 의해 수행되기 때문에 read(), write() 등의 보다 추상화된 시스템콜 함수보다 훨씬 저수준으로 버퍼링이 구현되는 듯 하다.)
- 메모리(커널의 버퍼)에 로드된 코드들을 4번에서 할당한 주소공간에 매핑(mapping)한다.
- 프로그램의 시작 지점인 진입점(Entry Point) 주소를 설정한다.
- 프로세스의 상태를 실행 가능한 상태로 변경하고, 프로세스 스케줄러에 의해 실행을 시작한다.
현대에는 실행파일의 모든 코드를 메모리로 옮기는 것은 아니고, 페이징과 스와핑 기법 덕분에 필요한 코드만 옮기게 된다.
쓰레드
쓰레드는 프로세스 내에서 실행되는 실행 단위이다. 각 쓰레드는 프로세스의 자원을 공유하면서 독립적인 실행 흐름을 가진다.
자신만의 실행 흐름(= 실행 Context)는 독립된 스택, 쓰레드 로컬 스토리지 등을 통해 보장된다. 이는 쓰레드가 프로세스의 자원을 공유하면서도 독립적으로 실행될 수 있게 한다.
쓰레드의 필요성
근데, 프로세스한테 실행 단위, 독립적인 실행 흐름이라는 게 왜 필요할까?
그 필요성은 실생활에서 접하는 인터넷 브라우저를 통해 예를 들어보면 확실히 와닿는다.
- 프로세스: 인터넷 브라우저(크롬, IE)를 실행할 때, 운영 체제는 브라우저를 위한 프로세스를 생성한다. 이 프로세스는 브라우저가 필요로 하는 모든 자원(메모리, 파일 핸들 등)을 관리한다.
- 쓰레드: 브라우저 내부에서는 여러 쓰레드가 동시에 작동한다.
- 예를 들어, 한 쓰레드는 웹 페이지를 렌더링(화면에 표시)하는 데 사용되고, 다른 쓰레드는 사용자의 입력을 처리하며, 또 다른 쓰레드는 백그라운드에서 파일을 다운로드한다.
- 웹 페이지 렌더링: 사용자가 웹 사이트를 방문할 때, 브라우저는 해당 페이지를 렌더링하기 위해 하나 이상의 쓰레드를 사용한다. 이 쓰레드들은 HTML, CSS, 자바스크립트 등을 처리하여 페이지를 화면에 표시한다.
- 사용자 인터페이스(UI) 처리: 동시에 다른 쓰레드는 사용자의 입력(마우스 클릭, 키보드 입력 등)을 처리한다. 이 쓰레드는 브라우저의 반응성을 유지하는 데 중요합니다.
- 백그라운드 작업: 파일 다운로드나 데이터 동기화 같은 백그라운드 작업을 또 하나의 쓰레드가 맡는다.
이처럼, 하나의 프로세스여도 여러가지 작업을 동시에 수행하고 있다. 각 작업은 독립적으로 수행되고 있다.
이러한 상황을 멀티 쓰레딩이라고 한다.
반면 어떤 프로세스가 단 하나의 실행 흐름만을 가진다면 하나의 작업만 연속적으로 수행할 수밖에 없다. 단일 프로세스 환경에서 프로세스가 하나의 실행 흐름을 가지고 있다면, 이를 단일 쓰레드 프로세스라고 부를 수 있을 것이다.
이러한 방식은 현대의 복잡한 서비스들에서는 찾기 힘든 방식이다. 또한, 만약 장기간 대기해야 하는 상황에 처하게 된다면 그동안 다른 자원을 놀고 있을 수 밖에 없다. 이때 다른 작업을 수행하고 있으면 더 효율적이지 않을까?
따라서 더 나은 사용자 경험과 효율적인 자원 사용을 추구하다보니 하나의 프로세스 안에 더 세부적인 작업 흐름이 필요하게 되었고, 이것이 쓰레드이다.
(더 큰 범위에서 보면, 우리는 PC 카톡을 띄워놓으면서 브라우저도 띄워놓고, 동시에 여러 백그라운드 프로그램도 돌아가고 있다. 이처럼 다수의 프로세스가 동시에 실행되는 걸 멀티 프로세싱이라고 한다.)
쓰레드는 자원을 어떻게 할당받을까?
어떠한 프로세스의 여러 쓰레드들은 해당 프로세스의 자원을 공유한다. (즉, 그 가상메모리 공간 안에서만 놀 수 있다.)
쓰레드들은 자신이 종속된 프로세스의 가상 메모리 공간의 코드, 데이터, 힙, 스택 영역 각각의 일정 부분을 떼어서 할당받는다.
이 중에서 코드, 데이터, 힙 영역은 같은 프로세스의 다른 쓰레드와 공유하지만, 스택 영역은 쓰레드마다 독립적인 공간을 갖는다. 이는 데이터 공유를 효율적으로 하면서도, 스택 영역을 분리함으로써 각자의 실행 흐름을 독립적으로 유지하기 위한 조치이다.
가상 메모리의 일부를 떼어서 할당받는다는 말은 곧 서로 다른 쓰레드여도, 상위 프로세스의 가상 주소 체계를 공유한다는 뜻이다. 그러나 스택 영역 같은 경우에는 서로 상위 프로세스의 가상 주소 체계를 공유하긴 하지만, 서로의 스택 영역 주소에 직접 접근하려고 하는 건 OS의 메모리 보호 기능이 막는다.
이는 잘못된 접근이나 의도적인 공격은 시스템의 안정성을 해칠 수 있으며, 데이터 무결성 및 프로그램의 정확한 실행에 문제를 일으킬 수 있기 때문이다.
1. 간접적으로라도 다른 쓰레드의 스택 영역에 접근하는 경우는 매우 드뭅니다. 이는 일반적으로 권장되지 않는 방식이며, 프로그래밍 실수 또는 설계 오류에서 비롯될 수 있습니다. 예를 들어, 한 쓰레드가 다른 쓰레드의 스택에 저장된 지역 변수의 포인터를 전달받아 사용하는 경우, 이는 간접 접근에 해당하지만, 동시성 제어가 없으면 데이터 무결성 문제를 일으킬 수 있습니다.
2. 이러한 메모리 구조는 쓰레드가 서로의 자원을 공유하면서도, 각자의 실행 흐름을 독립적으로 유지할 수 있도록 설계된 것입니다. 이는 멀티쓰레딩 환경에서 데이터 공유의 효율성과 쓰레드의 독립성을 동시에 달성하기 위한 중요한 설계 요소입니다.
당연한 말일수도 있지만 쓰레드 생성은 프로세스 생성보다 가벼우며, 적은 리소스를 사용한다. 이러한 특징 덕에 멀티쓰레딩이 높은 처리량과 빠른 응답 시간을 제공할 수 있다.
- 프로세스 생애주기
- 쓰레드 생애주기
'Computer Science > 운영체제 (Operating System)' 카테고리의 다른 글
PintOS | Project1. Threads | Advanced Scheduling (4.4 BSD) (2) | 2023.12.04 |
---|---|
운영체제 | CPU 스케줄링 알고리즘 | MLFQ (0) | 2023.11.29 |
운영체제 | CPU 스케줄링 알고리즘 | RR, SJF, STCF (0) | 2023.11.26 |
운영체제 | 프로세스, 쓰레드의 상태와 생애주기 (0) | 2023.11.24 |
PintOS | Project1. Threads | 과제 소개 (1) | 2023.11.24 |