////
Search

2. 프로세스와 스레드

메모리엔 컴퓨터 실행 순간부터 다양한 프로세스들이 적재되어 실행됨
프로세스 유형
포그라운드 프로세스(foreground process) : 사용자가 보는 공간에서 사용자와 상호작용하며 실행
백그라운드 프로세스(background process) : 사용자가 보지 못하는 곳에서 실행
데몬(daemon) : 사용자와 별다른 상호작용 없이 주어진 작업만 수행하는 특별한 백그라운드 프로세스
프로세스 유형을 막론하고 하나의 프로세스를 구성하는 메모리 내 정보는 크게 다르지 않음. 커널 영역에는 프로세스 제어 블록(PCB)이라는 정보가 저장되고, 사용자 영역에는 실행 중인 프로세스가 코드 영역, 데이터 영역, 힙 영역, 스택 영역으로 나뉘어 저장

메모리 영역

정적 할당 영역 : 프로그램 실행 도중 크기가 변하지 않는 영역
코드 영역, 데이터 영역
동적 할당 영역 : 프로그램 실행 도중 크키가 변할 수 있는 영역
힙 영역, 스택 영역

1) 코드 영역(텍스트 영역)

실행 가능한 명령어가 저장되는 공간
CPU가 읽고 실행할 명령어가 담김 → 읽기 전용 공간

2) 데이터 영역

프로그램이 실행되는 동안 유지할 데이터가 저장되는 공간
정적 변수, 전역 변수
BSS 영역
BSS 영역까지 추가로 구분하는 경우도 존재. BSS 영역은 데이터 영역과 유사하지만 초기화 여부가 다름. 초기값이 있는 정적 변수나 전역 변수 같은 데이터는 데이터 영역에 저장. 초깃값이 없는 데이터는 BSS 영역에 저장

3) 힙 영역

프로그램을 만드는 사용자(= 개발자)가 직접 할당 가능한 저장 공간. 프로그램 실행 도중 비교적 자유롭게 할당하여 사용 가능한 메모리 공간
다만, 언젠가는 해당 공간을 반환해야하며 안 그러면 메모리 누수 문제(할당한 공간이 계속 메모리에 남아 메모리를 낭비) 초래 가능
가비지 컬렉션 기능을 통해 자체적으로 사용하지 않는 힙 메모리를 해체하는 기능을 제공하는 언어도 존재

4) 스택 영역

데이터 영역과 달리, 일시적으로 사용할 값들이 저장되는 공간
매개변수, 지역 변수, 함수 복귀 주소
스택 영역에는 스택 트레이스 형태의 함수 호출 정보가 저장될 수 있음
스택 트레이스 : 특정 시점에 스택 영역에 저장된 함수 호출 정보

PCB와 문맥 교환

운영체제가 메모리에 적재된 다수의 프로세스를 관리하려면, 프로세스를 식별 가능한 커널 영역 내 정보(= 프로세스 제어 블록[PCB])가 필요. PCB는 프로세스와 관련한 다양한 정보를 내포하는 구조체의 일종. 새로운 프로세스가 메모리에 적재(= 프로세스 생성)됐을 때 커널 영역에 만들어지고, 프로세스의 실행이 끝나면 폐기
보통 다음과 같은 정보들이 PCB에 담겨있음(운영체제마다 약간의 차이 존재) :
1.
PID(프로세스 ID) : 프로세스 식별 번호
2.
프로세스 실행 과정에서 사용한 레지스터 값
3.
프로세스 상태 : 프로세스의 현재 상태
4.
CPU 스케줄링(우선순위) 정보 : CPU를 할당받는 순서
5.
메모리 관련 정보 : 프로세스의 메모리상 적재 위치
6.
프로세스가 사용한 파일 및 입출력장치 관련 정보
여러 PCB들은 커널 내에서 프로세스 테이블(실행 중인 PCB 모음) 형태로 관리되는 경우가 대부분. 새롭게 실행되는 프로세스의 PCB는 프로세스 테이블에 추가하고 필요한 자원을 할당. 종료되는 프로세스의 PCB는 프로세스 테이블에서 삭제되고 자원을 해제
비정상 종료 상태 : 프로세스가 비정상 종료되어 사용한 자원이 회수되었음에도 프로세스 테이블에 종료된 프로세스의 PCB가 남아 있는 경우(= 좀비 프로세스)
일반적으로 메모리에 적재된 프로세스들은 한정된 시간 동안 번갈아 가며 실행됨. 이때, 프로세스가 실행된다는 말은 운영체제에 의해 CPU 자원을 할당받았다는 뜻(CPU가 프로세스를 구성하는 명령어와 데이터를 인출하고 실행하며, 운영체제가 CPU 자원을 할당하기 때문).1
프로세스의 CPU 사용 시간은 타이머 인터럽트에 의해 제한됨. 타이머 인터럽트란, 시간이 끝났음을 알리는 인터럽트로, 타임아웃 인터럽트라고도 부름.
프로세스 A가 OS로부터 CPU를 할당받아 실행되다가, 타이머 인터럽트가 발생해 프로세스 B로 CPU 사용을 양보해야하는 상황
프로세스 A는 각종 레지스터 값, 메모리 정보, 실행을 위해 열었던 파일, 사용한 입출력장치 등 지금까지의 중간 정보를 백업해야함. 백업 대상이 되는 중간 정보(= 프로세스 수행을 재개하기 위해 기억해야 할 정보)를 문맥(Context)이라고 함.
프로세스의 문맥은 해당 프로세스의 PCB에 명시됨. 프로세스의 CPU 사용 시간이 다 되거나 인터럽트가 발생하면 운영체제는 해당 프로세스의 PCB에 문맥을 백업하고, 뒤이어 실행할 프로세스의 문맥을 복구
이처럼 기존 프로세스의 문맥을 PCB에 백업하고, PCB에서 문맥을 복구해 새로운 프로세스를 실행하는 것문맥 교환(Context Switching)이라고 함(즉, 문맥 교환이란, 여러 프로세스가 끊임없이 빠르게 번갈아 가며 실행되는 원리)
그러나 문맥 교환이 너무 잦으면, 캐시 미스가 발생할 가능성이 높아져 메모리로부터 실행할 프로세스의 내용을 가져오는 작업이 빈번해지고 이는 큰 오버헤드로 이어질 수 있음

프로세스의 상태

프로세스는 여러 상태를 거치며 실행됨. 운영체제는 PCB를 통해 프로세스의 상태를 인식하고 관리함.

생성 상태(new)

프로세스를 생성 중인 상태 : 메모리에 적재되어 PCB를 할당받은 상태
실행할 준비가 완료된 프로세스는 준비 상태가 되어 CPU의 할당을 기다림

준비 상태(ready)

당장이라도 CPU를 할당받아 실행 가능하지만, 자신의 차례를 기다리고 있는 상태
준비 상태의 프로세스가 CPU를 할당받으면 실행 상태가 됨
디스패치(dispatch) : 실행 상태로 전환되는 것

실행 상태(running)

CPU를 할당받아 실행 중인 상태
타이머 인터럽트가 발생해 프로세스가 할당받은 시간을 모두 사용하면 다시 준비 상태로 전환되고, 실행 도중 입출력장치를 사용하여 입출력장치의 작업이 끝날 때까지 기다려야 하면 대기 상태로 전환

대기 상태(blocked)

프로세스가 입출력 작업을 요청하거나 바로 확보할 수 없는 자원을 요청하는 등 곧장 실행이 불가능한 조건에 놓이는 경우, 대기 상태로 전환
보통 전환되는 상황은 입출력 작업을 요구하는 경우가 대부분
대기 상태의 프로세스가 입출력 작업이 완료되는 등 실행 가능 상태가 되면 다시 준비 상태가 되어 CPU 할당을 대기

종료 상태(terminated)

프로세스가 종료된 상태
프로세스가 종료되면 운영체제는 PCB와 프로세스가 사용한 메모리를 정리

멀티프로세스와 멀티스레드

한 프로세스를 구성하는 코드를 동시에 실행하는 방법은?

방법 1) 멀티프로세스

같은 프로그램을 각기 다른 여러 프로세스로 생성해 실행하는 방법
EX) 웹 브라우저의 탭
동시에 여러 프로세스가 실행되는 것
중요한 점
각기 다른 프로세스들이 기본적으로 자원을 공유하지 않고, 독립적으로 실행
같은 작업을 수행하고 있지만 각각의 PID 값이 다르고, 프로세스별로 파일과 입출력장치 등의 자원이 독립적으로 할당되어 다른 프로세스에 영향을 거의 끼치지 않음

방법 2) 멀티스레드

멀티 스레드 : 프로세스를 동시에 실행하는 여러 스레드
하나의 스레드는 스레드를 식별 가능한 고유 정보인 스레드 ID, 프로그램 카운터, 레지스터 값, 스택 등으로 구성
스레드마다 각각의 프로그램 카운터 값과 스택 보유 → 스레드마다 다음에 실행할 주소를 가질 수 있고, 연산 과정의 임시 저장 값을 가질 수 있음

멀티프로세스 & 멀티스레드 비교

가장 큰 차이점 : 자원의 공유 여부
서로 다른 프로세스들은 기본적으로 자원 공유를 안 하므로 독립적으로 실행되고, 같은 프로세스를 실행하는 여러 스레드들은 프로세스 자원을 공유
스레드들은 동일 주소 공간의 코드, 데이터, 힙 영역을 공유하고 열린 파일 같은 프로세스의 자원을 공유하기 때문에 쉽게 협력하고 통신 가능
멀티프로세스 환경에서는 한 프로세스가 문제가 생겨도 다른 프로세스들에는 지장이 없거나 적지만, 멀티 스레드 환경에서는 한 스레드에 생긴 문제가 프로세스 전체 문제가 될 수 있음

프로세스 간 통신(IPC : Inter-Process Communication)

프로세스는 기본적으로 자원을 공유하지 않지만, 프로세스 간에도 자원을 공유하고 데이터를 주고받을 수 있는 방법(= IPC) 존재. 프로세스 간 통신이 이뤄지는 방식에는 크게 2가지 유형(공유 메모리, 메시지 전달) 존재
공유 메모리 : 데이터를 주고받는 프로세스가 공통적으로 사용할 메모리 영역을 두는 방식 메시지 전달 : 프로세스 간에 주고받을 데이터를 메시지의 형태로 주고받는 방식

방법1) 공유 메모리

프로세스 간에 공유하는 메모리 영역을 토대로 데이터를 주고받는 통신 방식. 공유 메모리라는 특별한 메모리 공간을 할당해 프로세스가 해당 메모리 공간을 공유하여 읽고 쓰기 가능
프로세스가 공유하는 메모리 영역을 확보하는 시스템 콜을 기반으로 수행되거나, 간단하게 프로세스가 공유하는 변수나 파일을 활용하는 방식이 존재
가장 중요한 특징
통신을 주고받는 각 프로세스가 마치 자신의 메모리 영역을 읽고 쓰는 것처럼 통신한다는 점
프로세스가 데이터를 주고받는 과정에 커널의 개입이 거의 없다는 점
프로세스가 주고받는 데이터가 커널 영역을 거치지 않는 경우가 많음
각 프로세스가 각자의 메모리 영역(사용자 영역)을 읽고 쓰는 것뿐이므로, 메시지 전달 방식보다 통신 속도가 빠름. 그러나 각 프로세스가 서로의 공유 메모리 영역을 동시에 읽고 쓸 경우, 데이터 일관성이 훼손될 수 있음(= 레이스 컨디션)

방법2) 메시지 전달

프로세스 간에 주고받을 데이터가 커널을 거쳐 송수신되는 통신 방식. 메시지 전달 기반 IPC는 메시지를 보내는 수단과 받는 수단이 명확하게 구분되어있음.
send() : 메시지를 보내는 시스템 콜
recv() : 메시지를 받는 시스템 콜
각 프로세스는 두 시스템 콜을 호출하며 메시지를 송수신 가능
각 프로세스 입장에서 메시지 전달 기반 IPC는 커널의 도움을 적극적으로 받으므로 레이스 컨디션, 동기화 등의 문제를 고려할 일이 적음. 그러나 주고받는 데이터가 커널을 통해 송수신되므로 공유 메모리 기반 IPC보다 통신 속도가 느림
메시지 전달 기반 IPC를 위한 대표 수단으로 파이프, 시그널, 소켓, 원격 프로시저 호출(RPC) 등이 있음

수단1) 파이프

먼저 파이프에 삽입된 데이터가 먼저 읽힘
익명 파이프(unnamed piped) : 단방향 프로세스 간의 통신 도구
지명 파이프(named piped) : 양방향 프로세스 간의 통신 도구

수단2) 시그널

프로세스에게 특정 이벤트가 발생했음을 알리는 비동기적인 신호
시그널 자체는 IPC만을 위해 존재하는 개념이 아니므로, 시그널을 적절히 활용해 IPC를 수행 가능하다 정도로만 이해하기
시그널 종류는 다양(= 시그널을 발생시키는 이벤트의 종류는 다양). 대부분은 인터럽트 관련 이벤트지만, 사용자가 직접 정의 가능한 시그널도 존재
아래는 리눅스 운영체제의 대표적인 시그널 예시
시그널
설명
기본 동작
SIGCHLD
자식 프로세스 종료
무시
SIGILL
허용하지 않은 명령어 실행
코어 덤프 생성 후 종료
SIGINT
키보드 인터럽트(Ctrl + C)
종료
SIGKILL
프로세스 종료(핸들러 재정의 불가능)
종료
SIGSEGV
잘못된 메모리 접근
코어 덤프 생성 후 종료
SIGTERM
프로세스 종료(핸들러 재정의 가능)
종료
SIGUSR1
사용자 정의 시그널
종료
SIGUSR2
사용자 정의 시그널
종료
프로세스는 시그널이 발생하면, 여느 인터럽트 처리 과정과 유사하게 하던 일을 잠시 중단하고 시그널 처리를 위한 시그널 핸들러를 실행한 뒤 실행 재개. 프로세스는 직접 특정 시그널을 발생시킬 수 있고, 직접 일부 시그널 핸들러를 (재)정의 가능
참고) 시그널의 기본 동작 & 코어 덤프

수단3) 원격 프로시저 호출(RPC)

원격 코드를 실행하는 IPC 기술. 다른 프로세스의 원격 코드 실행을 의미. RPC를 통해 프로그래밍 언어나 플랫폼과 무관하게 성능 저하를 최소화하고 메시지 송수신이 가능하기 때문에 대규모 트래픽 처리 환경, 특히 서버 간 통신 환경에서 사용하는 경우가 대부분
로컬 프로시저 호출 : 한 프로세스 내의 특정 코드 실행

수단4) 소켓

네트워크 소켓(소켓)택배를 보관 가능한 우체통과 같음.
두 프로세스가 소켓을 열고, 송신지 프로세스는 메시지를 소켓에 쓰고, 수신지 프로세스는 메시지를 소켓에서 획득. 즉, 소켓프로세스가 주고받는 데이터의 종착점(= 엔드포인트)과 같음. 그래서 소켓을 프로세스 간 네트워크 통신의 엔드포인트라고 정의하기도 함
소켓은 많은 운영체제에서 파일처럼 간주(= 프로세스가 열고, 읽고, 쓸 수 있는 대상). 보내고자 하는 메시지를 쓰면 네트워크를 통해 송신되고, 때로는 수신한 메시지를 읽어들일 수 있는 특별한 파일로 간주. 소켓을 향한 출력은 네트워크를 통한 송신, 소켓으로부터의 입력은 네트워크를 통한 수신과 동일.
운영체제가 파일 디스크립터로 파일을 식별하고 이를 통해 파일 입출력을 하듯이, 대부분 운영체제의 소켓도 (파일 디스크립터와 본질적으로 동일한) 소켓 디스크립터로 소켓을 식별하고 이를 통해 소켓 입출력이 가능. 또한 파일이 IPC의 수단이 되듯이, 소켓도 IPC의 수단으로 간주
소켓 입출력과 관련한 다양한 시스템 콜이 존재하며, 소켓을 이용하여 네트워크 송수신을 수행하는 프로세스들은 이러한 시스템 콜을 활용해 동작함. 간단한 요청/응답 메시지 송수신이더라도, 내부적으로 저수준에서는 다수의 소켓 입출력 시스템 콜이 호출되며 실행됨