본문 바로가기
Computer Science/OS

[ 혼자 공부하는 컴퓨터구조 + 운영체제 ] Chapter10. 프로세스와 스레드

by seoyeonnn 2024. 6. 11.

10-1. 프로세스 개요

(1) 프로세스 직접 확인하기

프로세스(process): 실행 중인 프로그램

포그라운드 프로세스(foreground process): 사용자가 보는 앞에서 실행되는 프로세스

백그라운드 프로세스(background process): 사용자가 보지 못하는 뒤편에서 실행되는 프로세스

 

백그라운드 프로세스 중에는 사용자와 직접 상호작용할 수 있는 백그라운드 프로세스도 있지만, 사용자와 상호작용하지 않고 그저 묵묵히 정해진 일만 수행하는 백그라운드 프로세스도 있다.

이러한 백그라운드 프로세스를 유닉스 체계의 운영체제에서는 데몬(daemon)이라고 부르고, 윈도우 운영체제에서는 서비스(service)라고 부른다.

 

(2) 프로세스 제어 목록

프로세스는들은 차례대로 돌아가며 한정된 시간만큼만 CPU를 이용한다. 자신의 차례가 되면 정해진 시간만큼 CPU를 이용하고, 시간이 끝났음을 알리는 인터럽트(타이머 인터럽트)가 발생하면 자신의 차례를 양보하고 다음 차례가 올 때까지 기다린다.

타이머 인터럽트(= 타임아웃 인터럽트): 클럭 신호를 발생시키는 장치에 의해 주기적으로 발생하는 하드웨어 인터럽트

 

운영체제는 프로세스 제어 블록(PCB)을 이용하여 프로세스에 CPU를 비롯한 자원을 배분한다.

프로세스 제어 블록(PCB): 프로세스와 관련딘 정보를 저장하는 자료 구조

- PCB는 커널 영역에 생성된다.

- 운영체제는 수많은 프로세스들 사이에서 PCB로 특정 프로세스를 식별하고 해당 프로세스를 처리하는 데 필요한 정보를 판단한다.

- 프로세스 생성 시에 만들어지고 실행이 끝나면 폐기된다.

 

PCB에 담기는 정보는 대표적으로 다음과 같다.

- 프로세스 ID(PID)

: 특정 프로세스를 식별하기 위해 부여하는 고유한 번호 Ex. 학번, 사번

- 같은 일을 수행하는 프로그램이라 할지라도 두 번 실행하면 PID가 다른 두 개의 프로세스가 생성된다.]

 

- 레지스터 값

프로세스는 자신의 실행 차례가 돌아오면 이전까지 진행했던 작업들을 이어 실행하기 위해, 이전까지 사용했던 레지스터의 중간값들을 모두 복원한다.

 

- 프로세스 상태

현재 프로세스가 입출력장치를 사용하기 위해 기다리고 있는 상태인지, CPU를 사용하기 위해 기다리고 있는 상태인지, CPU를 이용하고 있는 상태인지 등의 상태 정보가 저장된다.

 

- CPU 스케줄링 정보

프로세스가 언제, 어떤 순서로 CPU를 할당받을지에 대한 정보도 기록된다.

 

- 메모리 관리 정보

베이스 레지스터, 한계 레지스터 값과 같은 프로세스가 어느 주소에 저장되어 있는지에 대한 정보가 담긴다.

 

- 사용한 파일과 입출력장치 목록

프로세스가 실행 과정에서 특정 입출력장치나 파일을 사용하면 PCB에 해당 내용이 명시된다.

 

(3) 문맥 교환

문맥(context): 하나의 프로세스 수행을 재개하기 위해 기억해야 할 정보

하나의 프로세스 문맥은 해당 프로세스의 PCB에 표현되어 있다.

 

문맥 교환(context switching): 기존 프로세스의 문맥을 PCB에 백업하고, 새로운 프로세스를 실행하기 위해 문맥을 PCB로부터 복구하여 새로운 프로세스를 실행하는 것

문맥 교환은 여러 프로세스가 끊임없이 빠르게 번갈아 가며 실행되는 원리가 되고, 문맥 교환이 자주 일어나면 프로세스는 그만큼 빨리 번갈아 가며 수행되기 때문에 동시에 실행되는 것처럼 보인다.

※ 문맥 교환을 너무 자주 하면 오버헤드가 발생할 수 있기 때문에 문맥 교환이 자주 일어난다고 해서 반드시 좋은 건 아니다.

 

(4) 프로세스의 메모리 영역

하나의 프로세스는 사용자 영역에 크게 코드 영역, 데이터 영역, 힙 영역, 스택 영역으로 나뉘어 저장된다.

코드 영역(code sement) = 텍스트 영역(text segment)

: 실행할 수 있는 코드, 즉 기계어로 이루어진 명령어가 저장된다.

- 데이터가 아닌 CPU가 실행할 명령어가 담겨 있기 때문에 쓰기가 금지되어 있는 읽기 전용(read-only) 공간이다.

 

데이터 영역(data segment)

: 잠깐 썼다가 없앨 데이터가 아닌 프로그램이 실행되는 동안 유지할 데이터가 저장되는 공간

Ex. 전역 변수: 프로그램이 실행되는 동안 유지되며, 프로그램 전체에서 접근할 수 있는 변수

 

코드 영역과 데이터 영역은 크기가 고정된 영역이라는 점에서 정적 할당 영역이라고 부른다.

 

힙 영역(heap segment)

: 프로그래머가 직접 할당할 수 있는 저장 공간

프로그래밍 과정에서 힙 영역에 메모리를 할당했다면 언젠가는 해당 공간을 반환해야 한다.

메모리 누수(memory leak): 메모리 공간을 반환하지 않아, 할당한 공간이 메모리 내에 계속 남아 초래되는 메모리 낭비

 

스택 영역(stack segment)

: 데이터를 일시적으로 저장하는 공간

데이터 영역에 담기는 값과는 달리 잠깐 쓰다가 말 값들이 저장된다.

Ex. 매개 변수, 지역 변수

 

힙 영역과 스택 영역은 실시간으로 그 크기가 변할 수 있기 때문에 동적 할당 영역이라고 부른다.

일반적으로 힙 영역은 메모리의 낮은 주소에서 높은 주소로 할당되고, 스택 영역은 높은 주소에서 낮은 주소로 할당되어 새롭게 할당되는 주소가 겹치지 않도록 한다.

 

 

10-2. 프로세스 상태와 계층 구조

(1) 프로세스의 상태

 

생성 상태(new): 프로세스를 생성 중인 상태

이제 막 메모리에 적재되어 PCB를 할당받은 상태이다.

 

준비 상태(ready): CPU를 할당받아 실행할 수 있지만, 아직 차례가 아니기에 기다리고 있는 상태

디스패치(dispatch): 준비 상태인 프로세스가 실행 상태로 전환되는 것

 

실행 상태(running): CPU를 할당받아 실행 중인 상태

 

대기 상태(blocked): 입출력장치의 작업을 기다리는 상태

프로세스는 실행 도중 입출력장치를 사용하는 경우가 있는데, 입출력 작업은 CPU에 비해 처리 속도가 느리기에, 입출력을 끝날 때까지 기다려야 한다.

 

종료 상태(terminated): 프로세스가 종료된 상태

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

 

(2) 프로세스 계층 구조

프로세스는 실행 도중 시스템 호출을 통해 다른 프로세스를 실행할 수 있다.

부모 프로세스(parent process): 새 프로세스를 생성한 프로세스

자식 프로세스(child process): 부모 프로세스에 의해 생성된 프로세스

 

많은 운영체제는 프로세스가 프로세스를 낳는 계층적인 구조로써 프로세스들을 관리한다.

Ex. 사용자가 컴퓨터를 켜고 로그인 창을 통해 로그인해서 bash 셸로 Vim이라는 문서 편집기 프로그램을 실행

※ 최초의 프로세스 PID는 항상 1번이며, 모든 프로세스 최상단에 있는 부모 프로세스이다. 유닉스 운영체제에서는 init, 리눅스 운영체제에서는 systemd, macOS에서는 launchd라고 한다.

 

(3) 프로세스 생성 기법

부모 프로세스는 fork를 통해 자신의 복사본을 자식 프로세스로 생성해 내고, 만들어진 복사본(자식 프로세스)은 exec를 통해 자신의 메모리 공간을 다른 프로그램으로 교체한다.

 

fork: 자기 자신 프로세스의 복사본을 자식 프로세스로 생성하는 시스템 호출

자식 프로세스는 부모 프로세스의 복사본이기 때문에 부모 프로세스의 자원들이 상속된다.

※ 복사된 자식 프로세스라 할지라도 PID값이나 저장된 메모리 위치는 다르다.

 

exec: 자신의 메모리 공간을 새로운 프로그램으로 덮어쓰는 시스템 호출

exec를 호출하면 코드 영역과 데이터 영역의 내용이 실행할 프로그램의 내용으로 바뀌고, 나머지 영역은 초기화된다.

 

자식 프로세스가 exec를 호출하지 않는 경우도 있는데, 이 경우 부모 프로세스와 자식 프로세스는 같은 코드를 병행하며 실행하는 프로세스가 된다.

 

 

10-3. 스레드

(1) 프로세스와 스레드

스레드: 프로세스를 구성하는 실행의 흐름 단위

스레드를 이용하면 하나의 프로세스에서 여러 부분을 동시에 실행할 수 있다.

 

단일 스레드 프로세스: 실행의 흐름 단위가 하나인 프로세스

멀티 스레드 프로세스: 한 번에 여러 명령어를 동시에 실행할 수 있는 프로세스

 

스레드는 프로세스 내에서 각기 다른 스레드 ID, 프로그램 카운터를 비롯한 레지스터 값, 스택을 가지고 있기에 스레드마다 각기 다른 코드를 실행할 수 있다.

 

프로세스의 스레드들은 실행에 필요한 최소한의 정보(프로그램 카운터를 포함한 레지스터, 스택)만을 유지한 채 프로세스 자원을 공유하며 실행된다.

※ 많은 운영체제가 프로세스와 스레드를 구분하지만, 리눅스는 프로세스와 스레드 모두 실행의 문맥이라는 점에서 동등하다고 간주하고 이 둘을 크게 구분 짓지 않는다.

 

(2) 멀티프로세스와 멀티스레드

멀티프로세스: 여러 프로세스를 동시에 실행하는 것

멀티스레드: 여러 스레드로 프로세스를 동시에 실행하는 것

 

프로세스끼리는 기본적으로 자원을 공유하지 않지만, 스레드끼리는 같은 프로세스 내의 자원을 공유한다.

 

프로세스를 fork하여 같은 작업을 하는 동일한 프로세스를 실행하면, 같은 프로그램을 실행하기 위해 메모리에 동일한 내용들이 중복해서 존재하게 된다.

반면 스레드들은 프로세스가 가지고 있는 자원을 공유하기 때문에, 여러 프로세스를 병행 실행하는 것보다 메모리를 더 효율적으로 사용할 수 있다.

 

멀티프로세스 환경에서는 하나의 프로세스에 문제가 생겨도 다른 프로세스에는 지장이 적거나 없지만, 멀티스레드 환경에서는 하나의 스레드에 문제가 생기면 프로세스 전체에 문제가 생길 수 있다는 단점도 존재한다.

 

프로세스 간 통신(IPC) : 프로세스는 기본적으로 자원을 공유하지 않지만, 프로세스끼리도 자원을 공유하고 데이터를 주고받을 수 있다.