Unisquads
로그인
홈
이용약관·개인정보처리방침·콘텐츠정책·© 2026 Unisquads
이용약관·개인정보처리방침·콘텐츠정책
© 2026 Unisquads. All rights reserved.

프로세스와 스레드 (r1)

이 문서의 과거 버전 (r1)을 보고 있습니다. 수정일: 2026.02.13 07:12

프로세스와 스레드

분류

컴퓨터 과학 > 운영 체제

정의

운영 체제가 프로그램 실행을 관리하는 기본 단위

주요 개념

프로세스, 스레드

관련 용어

멀티태스킹, 멀티스레딩, 컨텍스트 스위칭, 주소 공간

차이점 핵심

프로세스는 독립된 자원 할당 단위, 스레드는 프로세스 내 실행 흐름 단위

상세 비교 및 설명

프로세스 정의

실행 중인 프로그램의 인스턴스로, 독립된 메모리 공간, 자원, 실행 상태를 가짐

스레드 정의

프로세스 내에서 실행되는 세부 작업 단위. 동일 프로세스의 스레드는 메모리와 자원을 공유

프로세스 구성 요소

코드 섹션, 데이터 섹션, 힙, 스택, 프로세스 제어 블록(PCB)

스레드 구성 요소

스레드 ID, 프로그램 카운터, 레지스터 집합, 스택

생성 방법

프로세스: fork(), exec() (유닉스 계열) / 스레드: pthread_create(), 새로운 Thread 객체 생성

컨텍스트 스위칭 비용

프로세스 간 전환은 높음 (메모리 맵 등 변경). 스레드 간 전환은 낮음 (동일 주소 공간)

통신(IPC)

프로세스: 파이프, 메시지 큐, 공유 메모리, 소켓 / 스레드: 공유 변수 (동기화 필요)

동기화 필요성

스레드는 자원 공유로 인해 뮤텍스, 세마포어 등 동기화 메커니즘 필수

장단점 (프로세스)

장점: 고립성, 안정성 / 단점: 생성·전환 비용高, 통신 복잡

장단점 (스레드)

장점: 생성·전환·통신 비용低, 응답성 향상 / 단점: 디버깅 복잡, 한 스레드 문제가 전체 영향

사용 예시

프로세스: 독립적인 애플리케이션(브라우저, 문서 편집기) / 스레드: 웹 서버의 다중 연결 처리, GUI 애플리케이션의 백그라운드 작업

1. 개요

프로세스는 실행 중인 프로그램을 의미하며, 운영체제로부터 독립된 자원(메모리, 파일, CPU 시간 등)을 할당받는 작업의 단위이다. 각 프로세스는 자신만의 주소 공간과 프로세스 제어 블록(PCB)을 가지며, 다른 프로세스와 분리되어 실행된다.

반면, 스레드는 하나의 프로세스 내에서 실행되는 흐름의 단위이다. 스레드는 프로세스가 할당받은 자원(메모리, 파일 핸들 등)을 공유하면서 실행되며, 각 스레드는 별도의 프로그램 카운터와 스택 영역을 가진다. 이로 인해 하나의 프로세스 내에서 여러 작업을 동시에 수행하는 멀티스레딩이 가능해진다.

프로세스와 스레드의 핵심 차이는 자원 공유와 독립성에 있다. 프로세스는 서로 격리되어 있어 안정성이 높지만, 문맥 교환 비용이 크고 프로세스 간 통신(IPC)이 복잡하다. 스레드는 자원을 공유해 생성 및 통신 비용이 적고 응답성이 뛰어나지만, 하나의 스레드 문제가 전체 프로세스에 영향을 줄 수 있다.

이 개념들은 현대 운영체제와 소프트웨어 설계의 기초를 이루며, 멀티태스킹, 병렬 처리, 분산 시스템의 성능과 효율성을 결정하는 중요한 요소이다.

2. 프로세스의 정의와 특징

프로세스는 실행 중인 프로그램을 의미한다. 디스크에 저장된 정적인 명령어와 데이터의 집합인 프로그램이 메모리에 적재되어 운영체제에 의해 실행되는 동적인 개체가 프로세스가 된다. 각 프로세스는 운영체제로부터 독립된 자원을 할당받으며, 이는 가상 주소 공간, 파일 디스크립터, 보안 속성 등을 포함한다.

프로세스의 모든 정보는 프로세스 제어 블록(PCB)이라는 자료 구조에 저장되어 관리된다. PCB는 운영체제가 프로세스를 스케줄링하고 상태를 관리하는 데 필요한 핵심 정보를 담고 있다. 주요 구성 요소는 다음과 같다.

구성 요소

설명

프로세스 식별자(PID)

프로세스를 고유하게 식별하는 번호

프로세스 상태

실행, 준비, 대기 등의 현재 상태

프로그램 카운터(PC)

다음에 실행할 명령어의 주소

CPU 레지스터

누산기, 인덱스 레지스터 등

메모리 관리 정보

기준 레지스터, 한계 레지스터, 페이지 테이블 등

입출력 상태 정보

프로세스에 할당된 입출력 장치, 열린 파일 목록

계정 정보

CPU 사용 시간, 시간 제한 등

프로세스는 실행 과정에서 여러 상태를 거치며 변화한다. 일반적인 상태 변화 모델은 다음과 같다. 생성된 프로세스는 준비 상태가 되어 CPU 할당을 기다린다. 스케줄러에 의해 선택되면 실행 상태로 전환되어 명령어를 수행한다. 실행 중 입출력 요청 등의 사건이 발생하면 대기 상태로 전환되고, 해당 사건이 완료되면 다시 준비 상태로 돌아간다. 실행이 완료되면 종료 상태가 되어 모든 자원을 반납한다.

2.1. 프로세스의 개념

프로세스는 실행 중인 프로그램을 의미한다. 디스크에 저장된 정적인 명령어와 데이터의 집합인 프로그램과 달리, 프로세스는 그 프로그램이 메모리에 적재되어 운영체제에 의해 실행되는 동적인 실체이다. 운영체제는 각 프로세스에게 독립된 주소 공간, CPU 시간, 파일, 입출력 장치 등의 자원을 할당하고 관리한다.

프로세스는 최소한 하나의 실행 흐름, 즉 스레드를 포함하며, 고유한 프로세스 식별자(PID)로 구분된다. 각 프로세스는 일반적으로 코드(텍스트 섹션), 데이터, 힙(Heap) 영역, 스택(Stack) 영역으로 구성된 독립된 메모리 공간을 가진다. 이로 인해 한 프로세스의 메모리는 다른 프로세스가 직접 접근할 수 없으며, 이는 시스템의 안정성과 보안을 보장하는 핵심 메커니즘이다.

프로세스의 생명주기는 생성, 준비, 실행, 대기, 종료 등의 상태를 거친다. 프로세스는 fork()나 exec() 같은 시스템 호출을 통해 생성되며, 작업이 완료되거나 강제 종료되면 소멸한다. 운영체제는 프로세스 제어 블록(PCB)에 각 프로세스의 상태, 프로그램 카운터, 레지스터 정보, 메모리 관리 정보 등을 기록하여 관리한다.

구성 요소

설명

코드(텍스트)

실행할 프로그램의 명령어가 저장된 영역

데이터

전역 변수와 정적 변수가 저장된 영역

힙(Heap)

동적으로 할당되는 메모리 영역

스택(Stack)

함수 호출 시의 지역 변수와 반환 주소 등을 저장하는 영역

2.2. 프로세스 제어 블록(PCB)

프로세스 제어 블록(PCB)은 운영체제가 프로세스를 관리하기 위해 유지하는 자료 구조이다. 각 프로세스가 생성될 때마다 고유한 PCB가 만들어지며, 프로세스가 종료되면 PCB도 함께 소멸된다. 운영체제는 실행 중인 모든 프로세스의 PCB를 관리하여 프로세스 스케줄링과 상태 관리를 수행한다.

PCB에는 프로세스를 식별하고 상태를 복원하는 데 필요한 모든 정보가 담겨 있다. 주요 구성 요소는 다음과 같다.

구성 요소

설명

프로세스 식별자(PID)

운영체제가 각 프로세스에 부여하는 고유 번호이다.

프로세스 상태

프로세스의 현재 상태(예: 실행, 준비, 대기)를 나타낸다.

프로그램 카운터(PC)

다음에 실행할 명령어의 주소를 가리킨다.

CPU 레지스터

프로세스 실행 중 사용된 레지스터 값(누산기, 인덱스 레지스터 등)이 저장된다.

CPU 스케줄링 정보

프로세스의 우선순위, 스케줄링 큐 포인터 등의 정보를 포함한다.

메모리 관리 정보

베이스 레지스터, 한계 레지스터, 페이지 테이블 또는 세그먼트 테이블 포인터 등이 있다.

계정 정보

CPU 사용 시간, 시간 제한, 계정 번호 등을 기록한다.

입출력 상태 정보

프로세스에 할당된 입출력 장치와 열린 파일 목록이 있다.

문맥 교환(Context Switch)이 발생하면, 실행 중이던 프로세스의 상태(레지스터 값, 프로그램 카운터 등)를 해당 프로세스의 PCB에 저장한다. 그 후 실행할 프로세스의 PCB에서 저장된 상태를 복원하여 CPU에 적재한다. 이 과정을 통해 프로세스는 중단된 지점부터 정확히 실행을 재개할 수 있다. 따라서 PCB는 프로세스의 실행 역사를 보관하는 핵심 데이터 구조 역할을 한다.

2.3. 프로세스의 상태 변화

프로세스는 실행 중에 여러 상태를 거치며 변화한다. 이러한 상태 변화는 운영체제의 프로세스 스케줄링에 의해 관리되며, 일반적으로 다섯 가지 기본 상태로 모델링된다.

상태

설명

생성(New)

프로세스가 생성 중인 상태이다. 프로세스 제어 블록(PCB)이 할당되고 초기화된다.

준비(Ready)

프로세스가 프로세서(CPU)를 할당받기만을 기다리는 상태이다. 실행에 필요한 모든 자원은 이미 보유하고 있다.

실행(Running)

프로세스가 프로세서를 할당받아 명령어를 실행하고 있는 상태이다.

대기(Waiting)

프로세스가 입출력(I/O) 완료나 세마포어 신호와 같은 특정 사건을 기다리며 실행을 중단한 상태이다.

종료(Terminated)

프로세스의 실행이 완료되어 운영체제에 의해 자원이 회수되고 PCB가 정리되는 상태이다.

상태 변화는 특정 사건에 의해 트리거된다. 실행 상태의 프로세스는 타임 슬라이스가 만료되거나 더 높은 우선순위의 프로세스가 나타나면 준비 상태로 돌아간다. 또한, 입출력 요청과 같은 시스템 호출을 하면 대기 상태로 전환된다. 대기 상태의 프로세스는 기다리던 사건이 발생하면 준비 상태로 이동하여 다시 프로세서 할당을 기다린다. 준비 상태에서 실행 상태로의 전환은 스케줄러의 결정에 따라 이루어진다. 일부 시스템에서는 일시 중지(Suspend) 상태를 추가로 도입하여 메모리 부족 시 프로세스를 보조 저장장치로 이동시키기도 한다[1].

3. 스레드의 정의와 특징

스레드는 프로세스 내에서 실행되는 흐름의 단위이다. 하나의 프로세스는 최소 하나의 스레드(메인 스레드)를 가지며, 여러 개의 스레드를 생성하여 동시에 여러 작업을 수행할 수 있다. 스레드는 프로세스의 코드, 데이터, 힙 영역을 공유하지만, 각 스레드는 독립적인 스택 영역과 레지스터 상태(프로그램 카운터 등)를 가진다. 이는 같은 프로세스 내의 스레드들이 메모리 자원을 공유하면서도 병렬적으로 실행될 수 있게 하는 기반이 된다.

스레드는 크게 사용자 스레드와 커널 스레드로 구분된다. 사용자 스레드는 사용자 수준의 스레드 라이브러리에 의해 생성 및 관리되며, 운영체제 커널은 이를 단일 프로세스로 인식한다. 반면 커널 스레드는 운영체제 커널에 의해 직접 지원되고 관리된다. 이에 따른 주요 차이는 다음과 같다.

특징

사용자 스레드

커널 스레드

구현 및 관리 주체

사용자 수준 라이브러리 (예: POSIX 스레드(pthreads))

운영체제 커널

커널 인식

프로세스 하나로 인식

각 스레드를 별도의 실행 단위로 인식

생성/전환 속도

빠름 (커널 호출 불필요)

상대적으로 느림 (커널 모드 전환 필요)

병행성

한 스레드가 블록되면 전체 프로세스가 블록됨

한 스레드가 블록되어도 다른 스레드 실행 가능

스레드 사용의 주요 장점은 다음과 같다. 첫째, 프로세스 생성에 비해 스레드 생성과 문맥 교환 비용이 적게 든다. 둘째, 프로세스 내 자원을 공유하므로 스레드 간 통신이 간단하고 빠르다. 셋째, 여러 스레드가 병행 실행되어 응답성과 처리율을 높일 수 있다. 반면, 단점도 존재한다. 한 스레드의 오류가 전체 프로세스를 중단시킬 수 있으며, 공유 자원에 대한 접근 시 동기화 문제가 발생할 수 있다. 또한 사용자 스레드 모델에서는 하나의 스레드가 입출력 작업으로 블록되면 프로세스 내 모든 스레드가 대기해야 하는 문제가 있다.

3.1. 스레드의 개념

스레드는 프로세스 내에서 실행되는 흐름의 단위이다. 하나의 프로세스는 최소 하나의 스레드(메인 스레드)를 가지며, 여러 개의 스레드를 생성하여 동시에 작업을 수행할 수 있다. 이를 멀티스레딩이라고 한다. 스레드는 프로세스의 코드, 데이터, 힙 영역과 같은 자원을 공유하지만, 각 스레드는 독립적인 스택 영역과 프로그램 카운터, 레지스터 집합을 가진다.

스레드는 프로세스에 비해 생성 및 문맥 교환 비용이 적게 든다. 이는 스레드가 메모리 공간을 공유하기 때문에 새로운 주소 공간을 할당하거나 복사할 필요가 없기 때문이다. 또한, 같은 프로세스 내의 스레드들은 데이터와 힙 영역을 공유하기 때문에 통신이 간편하지만, 이로 인해 동기화 문제가 발생할 수 있다.

스레드는 크게 사용자 스레드와 커널 스레드로 구분된다. 사용자 스레드는 사용자 수준의 라이브러리에 의해 관리되고, 커널 스레드는 운영체제 커널에 의해 직접 관리된다. 이 두 모델의 차이는 스케줄링과 블로킹 처리 방식에 영향을 미친다.

특징

프로세스

스레드

자원 할당

독립된 메모리 공간(코드, 데이터, 힙)

프로세스의 자원 공유

독립적 요소

별도의 주소 공간, 파일 디스크립터 등

독립적인 스택, 레지스터, 프로그램 카운터

생성/소멸 비용

높음

낮음

통신

IPC 기법 필요(복잡)

공유 메모리를 통해 간단히 가능

문맥 교환 비용

높음

낮음

3.2. 사용자 스레드 vs 커널 스레드

스레드는 운영체제에 의해 관리되는 방식에 따라 사용자 스레드와 커널 스레드로 구분된다. 이 구분은 스레드의 생성, 스케줄링, 관리 주체가 어디에 있는지에 따라 결정된다.

사용자 스레드는 커널의 지원 없이 사용자 수준의 스레드 라이브러리에 의해 완전히 관리된다. 운영체제는 이 스레드들의 존재를 인식하지 못하며, 하나의 프로세스를 단일 실행 단위로 본다. 따라서 스레드 간의 전환에 커널 모드로의 전환이 필요 없어 문맥 교환 비용이 매우 낮다. 그러나 한 스레드가 블로킹 시스템 호출을 하면, 운영체제는 해당 프로세스 전체를 블록 상태로 간주하기 때문에 같은 프로세스 내의 다른 모든 스레드도 실행을 멈추게 된다는 단점이 있다. 또한 멀티프로세서 시스템에서 여러 스레드를 서로 다른 CPU에 동시에 분배하는 진정한 병렬 처리를 구현하기 어렵다.

반면, 커널 스레드는 운영체제 커널이 직접 생성하고 스케줄링한다. 각 스레드는 커널이 인식하는 독립적인 스케줄링 단위가 된다. 따라서 한 스레드가 블록되어도 같은 프로세스 내의 다른 스레드는 계속 실행될 수 있다. 또한 멀티프로세서 환경에서 하나의 프로세스에 속한 여러 스레드가 서로 다른 프로세서에서 동시에 실행될 수 있다. 단점은 스레드 간 전환 시 커널 모드로의 전환이 필수적이어서 사용자 공간에서의 전환보다 문맥 교환 비용이 더 크다는 점이다.

특징

사용자 스레드

커널 스레드

구현 및 관리 주체

사용자 공간의 스레드 라이브러리 (예: POSIX Pthreads)

운영체제 커널

운영체제 인식

인식하지 않음 (프로세스 단위 관리)

인식함 (스레드 단위 관리)

생성/관리 속도

빠름 (커널 개입 없음)

상대적으로 느림 (시스템 호출 필요)

문맥 교환 비용

낮음

높음

블로킹 영향

한 스레드 블록 시 전체 프로세스 블록

한 스레드 블록해도 다른 스레드 실행 가능

다중 처리기 지원

어려움

용이함 (진정한 병렬 처리 가능)

일부 시스템은 혼합형 스레딩 모델을 사용하여 두 방식을 결합하기도 한다. 예를 들어, 여러 사용자 스레드가 더 적은 수의 커널 스레드에 매핑되어, 사용자 수준의 효율성과 커널 수준의 병렬성 장점을 모두 취하려고 시도한다.

3.3. 스레드의 장점과 단점

스레드는 프로세스 내에서 실행되는 흐름의 단위로, 같은 프로세스에 속한 스레드들은 메모리 공간과 자원을 공유한다. 이 구조는 여러 장점을 제공하지만, 동시에 특정 단점과 주의 사항을 수반한다.

스레드 사용의 가장 큰 장점은 효율성이다. 새로운 프로세스를 생성하는 것에 비해 스레드를 생성하고 문맥을 전환하는 비용이 훨씬 적게 든다. 또한, 같은 프로세스 내의 스레드들은 힙 메모리, 파일 핸들, 전역 변수 등의 자원을 공유하기 때문에 데이터 교환이 쉽고 빠르다. 이는 스레드 간 통신이 복잡한 프로세스 간 통신 기법보다 간단하다는 의미이다. 멀티코어 또는 멀티프로세서 시스템에서는 여러 스레드를 각각 다른 코어에서 동시에 실행함으로써 진정한 병렬 처리를 달성하고 응용 프로그램의 성능을 크게 향상시킬 수 있다.

반면, 스레드는 공유 자원에 대한 접근으로 인해 복잡성을 증가시킨다. 한 스레드가 프로세스의 자원을 변경하면 다른 모든 스레드에 그 영향이 즉시 반영되므로, 동기화 없이는 데이터의 일관성이 깨질 위험이 크다. 이로 인해 경쟁 상태나 교착 상태와 같은 문제가 발생할 수 있다. 또한, 프로세스 내의 한 스레드가 비정상적으로 종료되거나 오류를 발생시키면, 공유 메모리 공간이 오염되어 전체 프로세스와 그 안의 다른 모든 스레드가 영향을 받고 종료될 수 있다. 이는 프로세스 간의 강력한 격리 보호가 없다는 단점이다.

장점

단점

생성 및 문맥 교환 비용이 낮음

공유 자원 접근으로 인한 동기화 문제 발생

자원 공유로 인한 효율적 통신

한 스레드의 오류가 전체 프로세스를 중단시킬 수 있음

멀티코어 시스템에서의 효과적인 병렬 처리 가능

설계와 디버깅이 복잡함

응용 프로그램의 응답성 향상

과도한 스레드 생성은 오히려 성능을 저하시킬 수 있음[2]

따라서 스레드를 사용할 때는 뮤텐스나 세마포어와 같은 동기화 메커니즘을 통해 공유 자원을 보호하고, 스레드의 수를 시스템 자원에 맞게 적절히 조정하는 것이 중요하다.

4. 프로세스와 스레드의 차이점

프로세스와 스레드는 모두 실행 흐름의 단위이지만, 자원 공유 방식, 생성 비용, 통신 방법 등에서 근본적인 차이를 보인다.

가장 큰 차이는 자원 공유 방식이다. 프로세스는 운영체제로부터 독립된 메모리 공간(코드, 데이터, 힙, 스택 영역)과 시스템 자원(파일 디스크립터 등)을 할당받아 실행된다. 따라서 기본적으로 한 프로세스는 다른 프로세스의 메모리에 직접 접근할 수 없다. 반면, 하나의 프로세스 내에 존재하는 여러 스레드는 코드, 데이터, 힙 영역과 같은 메모리 공간과 대부분의 시스템 자원을 공유한다. 각 스레드는 자신만의 독립적인 스택 영역과 레지스터 상태를 가지지만, 공유 메모리를 통해 데이터를 쉽게 교환할 수 있다.

이러한 구조적 차이는 생성 및 소멸 비용과 통신 방식에 직접적인 영향을 미친다. 프로세스는 독립된 메모리 공간을 구축해야 하므로 상대적으로 많은 시스템 자원과 시간이 소요된다. 반면 스레드는 이미 존재하는 프로세스의 자원을 공유하므로 생성과 문맥 교환(컨텍스트 스위칭)이 훨씬 가볍고 빠르다. 통신 측면에서 프로세스 간 통신(IPC)은 파이프, 메시지 큐, 공유 메모리 등 운영체제가 제공하는 특별한 메커니즘을 필요로 한다. 특히 공유 메모리를 제외하면 대부분 커널을 경유해야 하므로 오버헤드가 발생한다. 스레드는 기본적으로 같은 주소 공간을 공유하므로, 전역 변수나 힙 메모리를 통해 데이터를 쉽게 주고받을 수 있어 통신 비용이 매우 낮다.

비교 항목

프로세스

스레드

자원 할당

운영체제로부터 독립된 메모리와 자원을 할당받음

부모 프로세스의 메모리와 자원을 대부분 공유함

생성/소멸 비용

높음 (독립 공간 생성)

낮음 (공간 공유)

통신 방법

IPC 기법(파이프, 소켓, 공유 메모리 등) 필요

공유 메모리(전역 변수, 힙)를 통해 직접 접근 가능

독립성

하나의 프로세스가 비정상 종료해도 다른 프로세스에 영향이 적음

한 스레드의 오류가 전체 프로세스(다른 스레드 포함)의 종료로 이어질 수 있음

동기화 필요성

일반적으로 IPC 자체가 동기화 수단을 포함함

공유 자원 접근 시 명시적인 동기화(뮤텍스 등)가 필수적임

이러한 차이점으로 인해 안정성과 격리가 중요한 작업에는 프로세스가, 빠른 통신과 협력이 요구되는 작업에는 스레드가 각각 더 적합한 모델로 사용된다.

4.1. 자원 공유 방식

프로세스는 운영체제로부터 독립된 자원을 할당받아 실행되는 단위이다. 각 프로세스는 별도의 주소 공간(Code, Data, Heap, Stack 영역), 파일 디스크립터, 그리고 기타 시스템 자원을 독점적으로 소유한다. 따라서 한 프로세스가 가진 자원에 접근하려면 특별한 프로세스 간 통신(IPC) 메커니즘을 사용해야 한다. 이는 안정성 측면에서는 하나의 프로세스가 비정상 종료되어도 다른 프로세스에 직접적인 영향을 미치지 않는다는 장점이 있다.

반면, 스레드는 하나의 프로세스 내에서 생성되는 실행 흐름의 단위이다. 동일한 프로세스에 속한 모든 스레드는 프로세스가 가진 자원을 공유한다. 이들은 같은 주소 공간과 파일, 신호 등을 공유하기 때문에, 한 스레드가 전역 변수를 변경하면 다른 모든 스레드가 그 변경 사항을 즉시 볼 수 있다. 자원 공유의 정도를 비교하면 다음과 같다.

공유 자원

프로세스

스레드 (동일 프로세스 내)

코드(Text) 및 전역 데이터

별도 공간

공유

힙(Heap) 메모리

별도 공간

공유

스택(Stack) 메모리

별도 공간

스레드별 독립

파일 디스크립터

별도 공간

공유

레지스터 및 프로그램 카운터

별도 공간

스레드별 독립

이러한 자원 공유 방식의 차이는 성능과 복잡성에 직접적인 영향을 미친다. 스레드는 메모리와 같은 자원을 공유하므로 문맥 교환(Context Switch) 비용이 프로세스에 비해 훨씬 적고, 데이터 공유를 위한 통신 오버헤드도 낮다. 그러나 반대로, 공유 자원에 대한 동시 접근은 경쟁 조건(Race Condition)을 초래할 수 있어 뮤텍스나 세마포어와 같은 동기화 메커니즘을 반드시 사용해야 한다. 하나의 스레드가 오류로 비정상 종료되면 전체 프로세스가 종료될 위험도 있다.

4.2. 생성 및 소멸 비용

프로세스의 생성과 소멸은 상대적으로 많은 비용이 소모되는 작업이다. 새로운 프로세스를 생성하려면 운영체제는 프로세스 제어 블록(PCB)을 할당하고, 독립된 주소 공간과 자원(파일 디스크립터, 메모리 영역 등)을 새로이 설정해야 한다. 이는 부모 프로세스의 주소 공간을 복제하는 fork 시스템 호출과 새로운 프로그램을 메모리에 적재하는 exec 시스템 호출을 포함하는 경우가 많다. 이 과정은 메모리 할당, 페이지 테이블 구성, 자원 관리 테이블 업데이트 등 상당한 운영체제 오버헤드를 유발한다.

반면, 스레드는 이미 존재하는 프로세스 내에서 생성되므로 비용이 훨씬 적게 든다. 스레드는 프로세스의 자원(메모리 공간, 열린 파일 등)을 공유하기 때문에, 새로운 주소 공간을 만들 필요가 없다. 운영체제는 주로 새로운 스레드를 위한 스택 영역과 스레드 제어 블록(TCB)만을 할당하면 된다. TCB는 PCB보다 관리하는 정보가 훨씬 적기 때문에 생성 및 등록 속도가 빠르고, 문맥 교환(context switch) 시에도 공유 메모리 영역을 교체할 필요가 없어 오버헤드가 낮다.

이 차이는 시스템의 반응성과 확장성에 직접적인 영향을 미친다. 많은 수의 동시 작업을 빠르게 생성하고 종료해야 하는 서버 애플리케이션(예: 웹 서버)에서는, 프로세스 기반 모델보다 스레드 기반 모델이 훨씬 효율적이다. 스레드는 적은 비용으로 생성되어 요청을 처리하고 종료될 수 있기 때문이다. 아래 표는 주요 비용 요소를 비교한 것이다.

비용 요소

프로세스

스레드

메모리 공간

새로운 독립된 주소 공간 생성 및 할당 필요

프로세스의 기존 주소 공간 공유

자원 관리

파일, 소켓, 신호 처리기 등 대부분의 자원을 새로 설정 또는 복제

부모 프로세스의 자원을 대부분 공유

생성 시간

상대적으로 느림 (메모리 복제, 구조체 초기화 등)

상대적으로 빠름 (스택 및 TCB 생성 위주)

문맥 교환 비용

높음 (메모리 관리 장치(MMU) 갱신 필요)

낮음 (공유 메모리 영역은 교체 불필요)

따라서, 애플리케이션 설계 시 작업 단위의 빈번한 생성과 소멸이 예상된다면, 프로세스보다는 스레드를 사용하는 것이 시스템 성능에 유리하다. 그러나 스레드 간 동기화와 교착 상태 문제를 신중히 고려해야 한다.

4.3. 통신 및 동기화

프로세스 간 통신은 운영체제가 제공하는 별도의 IPC 메커니즘을 필요로 한다. 각 프로세스는 독립된 메모리 공간을 가지므로, 한 프로세스가 다른 프로세스의 데이터에 직접 접근하는 것은 불가능하다. 대신 공유 메모리, 파이프, 메시지 큐, 소켓 등의 방법을 통해 데이터를 교환한다. 이 과정은 상대적으로 무겁고 복잡하며, 커널의 개입이 필수적이다.

반면, 스레드는 동일한 프로세스 내에서 생성되므로 기본적으로 힙 메모리와 전역 변수 등의 자원을 공유한다. 따라서 한 스레드가 변경한 데이터를 다른 스레드가 즉시 접근하여 읽거나 수정할 수 있다. 이는 통신이 매우 효율적이고 빠르게 이루어질 수 있음을 의미한다.

그러나 자원의 공유는 동기화 문제를 필연적으로 동반한다. 여러 스레드가 공유 자원에 동시에 접근하여 값을 변경하려고 할 때, 실행 순서에 따라 예상치 못한 결과가 발생할 수 있다. 이를 경쟁 조건이라고 한다. 따라서 스레드 프로그래밍에서는 뮤텍스, 세마포어, 모니터 등의 동기화 기법을 사용하여 임계 구역에 대한 접근을 통제해야 한다.

정리하면, 프로세스 간 통신은 명시적인 IPC 기법을 필요로 하는 반면, 스레드 간 통신은 암묵적인 메모리 공유를 통해 이루어진다. 스레드의 효율적인 통신은 강력한 동기화 메커니즘의 사용을 전제로 한다.

5. 멀티프로세싱과 멀티스레딩

멀티프로세싱은 운영체제가 두 개 이상의 프로세스를 동시에 실행하는 방식을 말한다. 이는 하나의 컴퓨터 시스템에 여러 개의 CPU(코어)가 있거나, 단일 CPU에서 시분할 방식을 통해 동시에 실행되는 것처럼 보이게 한다. 각 프로세스는 독립된 메모리 공간을 할당받아 실행되므로, 한 프로세스의 오류나 비정상 종료가 다른 프로세스에 직접적인 영향을 미치지 않는다는 장점이 있다. 그러나 프로세스 간에 데이터를 공유하려면 IPC와 같은 별도의 통신 메커니즘이 필요하며, 문맥 교환 비용이 상대적으로 크다는 단점이 있다.

멀티스레딩은 하나의 프로세스 내에서 여러 개의 스레드를 생성하여 동시에 실행하는 기법이다. 모든 스레드는 부모 프로세스의 코드, 데이터, 힙 영역 등의 자원을 공유한다. 따라서 스레드 간의 데이터 교환은 공유 메모리를 통해 매우 효율적으로 이루어질 수 있다. 또한 스레드 간의 전환(문맥 교환)은 프로세스 간 전환보다 훨씬 빠르고 가볍다. 하지만 한 스레드가 프로세스의 공유 자원을 잘못 조작하면 같은 프로세스 내의 다른 모든 스레드에 문제가 전파될 수 있으며, 이로 인해 전체 프로세스가 중단될 위험이 있다.

두 방식의 적용 사례는 목표에 따라 다르다. 멀티프로세싱은 높은 안정성과 격리가 필요한 경우에 적합하다. 예를 들어, 웹 브라우저는 종종 탭이나 확장 프로그램을 별도의 프로세스로 실행하여 하나의 탭이 충돌해도 전체 브라우저가 종료되지 않도록 한다. 반면, 멀티스레딩은 공유 데이터에 대한 빠른 접근과 협력이 중요한 작업에 유리하다. 워드 프로세서는 사용자 입력을 처리하는 스레드, 문서 저장을 담당하는 스레드, 맞춤법 검사를 수행하는 스레드 등을 동시에 실행하여 응답성을 높인다.

특성

멀티프로세싱

멀티스레딩

기본 단위

프로세스

스레드

메모리 공간

독립적 (별도 할당)

공유 (같은 프로세스 내)

통신 비용

높음 ([[프로세스 간 통신

IPC]] 필요)

내결함성

높음 (프로세스 격리)

낮음 (한 스레드 오류가 전체 영향)

생성/전환 비용

높음

낮음

적합한 작업

격리와 안정성이 중요한 작업

협력과 데이터 공유가 빈번한 작업

5.1. 멀티프로세싱의 동작 방식

멀티프로세싱은 두 개 이상의 프로세스가 동시에 실행되는 것을 의미하며, 이는 단일 프로세서에서의 시분할 방식이나 여러 개의 프로세서를 활용하는 방식으로 구현된다. 핵심은 각 프로세스가 독립된 메모리 공간과 자원을 할당받아 실행된다는 점이다. 운영체제의 스케줄러는 CPU 시간을 여러 프로세스 사이에 할당하여, 사용자에게는 동시에 실행되는 것처럼 보이게 한다.

멀티프로세싱의 동작은 크게 대칭형 멀티프로세싱과 비대칭형 멀티프로세싱으로 구분된다. 대칭형 멀티프로세싱에서는 모든 프로세서가 동등한 지위를 가지며, 하나의 공유 메모리를 통해 작업을 조율한다. 반면, 비대칭형 멀티프로세싱에서는 하나의 마스터 프로세서가 작업을 분배하고 나머지 프로세서는 할당된 작업만을 수행하는 계층적 구조를 가진다.

구분

설명

특징

대칭형 멀티프로세싱

모든 프로세서가 동등하며, 공유 메모리를 통해 작업을 조율한다.

부하 분산이 효율적이고, 단일 프로세서 장애 시 시스템 신뢰성이 높다.

비대칭형 멀티프로세싱

마스터 프로세서가 작업을 통제하고 분배하며, 슬레이브 프로세서는 실행만 담당한다.

설계와 관리가 비교적 단순하지만, 마스터 프로세서에 병목 현상이 발생할 수 있다.

이러한 방식으로 동작하는 멀티프로세싱은 하나의 프로세스에 장애가 발생하더라도 다른 프로세스에는 영향을 주지 않아 시스템의 안정성을 높인다. 그러나 각 프로세스가 독립된 메모리 공간을 사용하기 때문에 프로세스 간 통신이 필요하며, 이로 인해 문맥 교환 비용과 통신 오버헤드가 발생하는 단점도 존재한다.

5.2. 멀티스레딩의 동작 방식

멀티스레딩은 하나의 프로세스 내에서 여러 개의 스레드를 생성하여 동시에 실행하는 기법이다. 이는 하나의 응용 프로그램이 동시에 여러 작업을 수행할 수 있게 한다. 멀티스레딩을 구현하는 시스템에서는 CPU가 매우 짧은 시간 간격으로 각 스레드를 번갈아 가며 실행하는 시분할 방식을 사용한다. 이로 인해 사용자에게는 여러 스레드가 동시에 실행되는 것처럼 보인다.

멀티스레딩 환경에서 스레드들은 프로세스가 할당받은 자원을 공유한다. 이는 코드 영역, 데이터 영역, 힙 영역 등의 메모리 자원과 열린 파일, 신호 처리기 등을 포함한다. 각 스레드는 독립적인 실행 흐름을 유지하기 위해 자신만의 스택, 프로그램 카운터, 레지스터 상태를 가진다. 운영체제의 스케줄러는 실행 가능한 스레드들 중 하나를 선택하여 CPU에 할당한다.

멀티스레딩의 동작은 사용되는 스레드 모델에 따라 달라진다. 사용자 스레드 모델에서는 스레드 생성, 관리, 스케줄링이 모두 사용자 수준의 스레드 라이브러리에 의해 이루어진다. 반면 커널 스레드 모델에서는 이러한 작업이 운영체제 커널에 의해 직접 처리된다. 하이브리드 스레드 모델은 두 방식을 혼합하여 사용한다.

멀티스레딩의 주요 이점은 다음과 같다.

이점

설명

응답성 향상

하나의 스레드가 입출력 대기 중일 때 다른 스레드가 작업을 계속할 수 있어 사용자 인터페이스의 반응성이 좋아진다.

자원 공유 효율

스레드 간 메모리와 자원을 공유하므로 프로세스 간 통신보다 통신 오버헤드가 적다.

경제성

프로세스 생성보다 스레드 생성 비용이 훨씬 적고, 문맥 교환 비용도 더 낮다.

다중 처리기 활용

멀티코어 또는 멀티프로세서 시스템에서 여러 스레드를 실제로 병렬 실행하여 성능을 극대화할 수 있다.

그러나 스레드들이 자원을 공유하기 때문에 동기화 문제가 발생할 수 있다. 임계 구역 문제를 해결하기 위해 뮤텍스, 세마포어, 모니터 등의 동기화 기법이 필수적으로 사용된다. 동기화를 잘못 관리하면 교착 상태나 경쟁 상태가 발생하여 프로그램이 오작동할 수 있다.

5.3. 적용 사례 비교

멀티프로세싱은 각 프로세스가 독립된 메모리 공간을 가지므로, 한 프로세스의 오류나 비정상 종료가 다른 프로세스에 직접적인 영향을 미치지 않는다는 장점이 있다. 이는 높은 안정성과 격리성이 요구되는 서버 환경, 특히 웹 브라우저의 탭이나 마이크로서비스 아키텍처에서 유리하게 작용한다. 반면, 프로세스 간 전환(문맥 교환) 비용이 크고, 프로세스 간 통신이 상대적으로 복잡하며 오버헤드가 발생할 수 있다.

멀티스레딩은 하나의 프로세스 내에서 여러 스레드가 메모리와 자원을 공유하므로, 데이터 공유와 통신이 효율적이고 빠르다. 이는 사용자 인터페이스 응답성 유지와 같은 작업에 적합하며, 대규모 계산 작업을 병렬로 처리하는 과학기술계산이나 동시 다중 연결을 처리하는 웹 서버에서 흔히 사용된다. 그러나 한 스레드의 오류가 전체 프로세스를 중단시킬 수 있으며, 공유 자원에 대한 접근을 관리하기 위한 복잡한 동기화 기법이 필수적이다.

아래 표는 두 방식의 주요 적용 사례를 비교하여 보여준다.

적용 분야

멀티프로세싱의 활용 예

멀티스레딩의 활용 예

웹 서버

안정성 중시: 각 클라이언트 요청을 독립 프로세스로 처리 (예: 전통적인 [[Apache HTTP Server

Apache]] prefork 방식)

데이터베이스 시스템

격리된 작업 처리: 쿼리 프로세서와 백그라운드 작업을 별도 프로세스로 실행

동시 트랜잭션 처리: 하나의 데이터베이스 인스턴스 내에서 여러 사용자 연결을 스레드로 관리

데스크톱 응용 프로그램

안정적 격리: 웹 브라우저에서 각 탭이나 확장 프로그램을 별도 프로세스로 실행 (예: Google Chrome)

반응형 UI: 사용자 인터페이스 스레드와 백그라운드 계산 스레드를 분리하여 화면 정지 방지

고성능 계산(HPC)

[[메시지 패싱 인터페이스

MPI]]를 이용한 대규모 분산 메모리 병렬 처리

현대 시스템은 두 방식을 혼합하여 사용하는 경우가 많다. 예를 들어, 하나의 응용 프로그램이 여러 프로세스로 구성되어 있고, 각 프로세스 내부에서 다시 멀티스레딩을 활용하는 멀티코어 환경이 대표적이다.

6. 프로세스 간 통신(IPC)

프로세스는 각각 독립된 메모리 공간을 할당받아 실행되므로, 다른 프로세스의 메모리에 직접 접근할 수 없다. 따라서 데이터를 교환하거나 작업을 조율하기 위해서는 운영체제가 제공하는 특별한 메커니즘이 필요하다. 이러한 메커니즘을 총칭하여 프로세스 간 통신(IPC)이라고 한다. IPC는 협력하는 프로세스들 사이에 정보를 공유하고 동작을 조정하는 데 필수적이다.

주요 IPC 기법은 크게 공유 메모리 방식과 메시지 전달 방식으로 나눌 수 있다. 공유 메모리 방식은 프로세스들이 일부 메모리 영역을 공통으로 매핑하여, 해당 영역을 통해 직접 데이터를 읽고 쓸 수 있게 한다. 이 방식은 통신 속도가 매우 빠르지만, 공유 자원에 대한 접근 제어를 위해 프로그래머가 명시적인 동기화를 구현해야 한다는 부담이 있다. 반면, 메시지 전달 방식은 운영체제의 커널을 통해 메시지를 송수신한다. 프로세스는 커널에 메시지를 보내고, 수신 프로세스는 커널로부터 메시지를 받는다. 이 방식은 커널이 중재하므로 구현이 비교적 간단하지만, 데이터 복사 오버헤드로 인해 공유 메모리 방식보다 일반적으로 느리다.

다양한 IPC 구현체가 존재하며, 각각의 특징과 사용 사례가 다르다. 다음은 주요 IPC 기법들을 정리한 표이다.

기법

유형

설명

주요 사용 예

파이프(Pipe)

메시지 전달

단방향 통신 채널. 부모-자식 프로세스 간에 주로 사용된다.

쉘에서 `ls \

명명된 파이프(Named Pipe / FIFO)

메시지 전달

파일 시스템에 이름이 존재하는 파이프. 무관계 프로세스 간 통신이 가능하다.

서버-클라이언트 구조의 통신

공유 메모리(Shared Memory)

공유 메모리

여러 프로세스가 동일한 메모리 세그먼트에 접근하여 고속 데이터 교환을 한다.

대용량 데이터를 빠르게 처리해야 하는 멀티미디어 응용

메시지 큐(Message Queue)

메시지 전달

커널이 관리하는 연결리스트 형태의 메시지 저장소. 메시지에 타입을 부여할 수 있다.

우선순위가 다른 작업들 간의 통신

소켓(Socket)

메시지 전달

네트워크를 통한 통신뿐만 아니라, 동일 호스트 내 프로세스 간 통신에도 사용된다.

네트워크 기반 분산 시스템, 로컬 통신(Unix Domain Socket)

세마포어(Semaphore) & 뮤텍스(Mutex)

동기화 도구

공유 자원에 대한 접근을 제어하는 동기화 수단으로, 주로 공유 메모리와 함께 사용된다.

공유 메모리 영역에 대한 상호 배제 구현

IPC 기법의 선택은 통신의 빈도, 전송 데이터의 크기, 프로세스 간 관계(부모-자식 여부), 그리고 필요한 통신 모델(단방향/양방향) 등 여러 요소에 따라 결정된다. 예를 들어, 고성능 컴퓨팅에서는 공유 메모리와 세마포어의 조합이, 네트워크 서비스에서는 소켓이 각각 선호되는 방식이다.

6.1. IPC의 필요성

프로세스는 일반적으로 독립된 메모리 공간을 할당받아 실행된다. 이는 한 프로세스가 다른 프로세스의 메모리 영역을 직접 접근할 수 없음을 의미하며, 이로 인해 프로세스 간에 데이터를 교환하거나 작업을 조율하기 위해서는 특별한 통신 메커니즘이 필요하다. 이러한 메커니즘을 프로세스 간 통신(IPC)이라고 부른다.

IPC의 필요성은 크게 세 가지 측면에서 설명할 수 있다. 첫째, 정보 공유이다. 여러 사용자가 동일한 정보에 동시에 접근해야 할 필요가 있을 수 있다. 예를 들어, 공유 메모리를 통해 여러 프로세스가 대용량 데이터를 효율적으로 공유할 수 있다. 둘째, 계산 가속화이다. 하나의 작업을 여러 서브태스크로 나누어 각각 다른 프로세스가 병렬로 실행하게 함으로써 전체 실행 시간을 단축할 수 있다. 이때 서브태스크 간의 중간 결과를 주고받아야 한다. 셋째, 모듈성이다. 시스템을 독립적인 모듈(프로세스)로 설계할 경우, 모듈 간의 통신과 협력이 필요해진다. 이는 클라이언트-서버 모델과 같은 소프트웨어 구조에서 두드러지게 나타난다.

필요성

설명

예시

정보 공유

여러 프로세스가 동일한 자원이나 데이터에 접근해야 할 때

공유 데이터베이스 접근, 공유 설정 파일 읽기/쓰기

계산 가속화

작업을 분할하여 병렬 처리하고 결과를 통합할 때

대규모 수치 계산, 렌더링 파이프라인

모듈성 및 편의성

독립적으로 개발된 프로그램들이 협력하여 하나의 작업을 수행할 때

웹 브라우저(프로세스)와 웹 서버(프로세스) 간 통신

또한, IPC는 보안과 안정성 측면에서도 중요한 의미를 가진다. 프로세스의 메모리 공간이 분리되어 있기 때문에, 한 프로세스의 오류나 악의적인 동작이 다른 프로세스로 직접 전파되는 것을 방지할 수 있다. 통신은 운영체제가 제공하는 제어된 채널을 통해서만 이루어지므로, 시스템의 전체적인 견고함을 유지하는 데 기여한다. 따라서 IPC는 협력적이면서도 안전한 다중 프로세스 환경을 구축하기 위한 필수적인 기반이 된다.

6.2. 주요 IPC 기법

IPC를 구현하는 기법은 크게 공유 메모리 방식과 메시지 전달 방식으로 나눌 수 있다. 공유 메모리 방식은 프로세스들이 특정 메모리 영역을 공유하여 데이터를 직접 읽고 쓰는 방식이다. 이 방식은 통신 속도가 매우 빠르지만, 공유 메모리 영역에 대한 접근을 개발자가 직접 동기화해야 한다는 복잡성이 따른다. 반면, 메시지 전달 방식은 프로세스들이 운영체제가 제공하는 시스템 호출을 통해 메시지를 주고받는다. 이 방식은 커널이 통신의 동기화를 관리하므로 구현이 비교적 간단하지만, 데이터 복사에 따른 오버헤드가 존재한다.

주요 IPC 기법은 다음과 같이 구체화된다.

기법

유형

설명

파이프(Pipe)

메시지 전달

부모-자식 프로세스 간의 단방향 통신 채널이다. 일반 파이프는 동일한 프로세스에 의해 생성된 프로세스들 사이에서만 사용 가능하다.

명명된 파이프(Named Pipe, FIFO)

메시지 전달

파일 시스템에 이름이 존재하여, 관련 없는 프로세스들 사이에서도 양방향 통신이 가능하다.

공유 메모리(Shared Memory)

공유 메모리

여러 프로세스가 동일한 메모리 세그먼트에 접근할 수 있도록 매핑한다. 가장 빠른 IPC 방법이지만, 세마포어나 뮤텍스 같은 동기화 도구가 필수적으로 요구된다.

메시지 큐(Message Queue)

메시지 전달

커널이 관리하는 연결 리스트 형태의 큐에 메시지를 저장하고 전달한다. 각 메시지는 타입을 가지며, 타입에 따라 선택적으로 수신할 수 있다.

소켓(Socket)

메시지 전달

네트워크를 통한 통신뿐만 아니라, 동일한 호스트 내의 프로세스 간 통신(도메인 소켓)에도 사용된다.

메모리 매핑 파일(Memory-Mapped File)

공유 메모리

파일을 프로세스의 가상 메모리 공간에 매핑하여, 파일 I/O를 메모리 접근처럼 수행할 수 있게 한다. 여러 프로세스가 동일한 파일을 매핑하면 IPC 수단이 된다.

시그널(Signal)

메시지 전달

특정 이벤트가 발생했음을 프로세스에 비동기적으로 알리는 간단한 메커니즘이다. 제한된 정보만을 전달할 수 있어 복잡한 데이터 교환에는 적합하지 않다.

이러한 기법들은 운영체제와 프로그래밍 환경에 따라 지원 수준과 API가 다르다. 예를 들어, 유닉스 계열 시스템에서는 파이프와 시그널이 역사적으로 널리 사용되었으며, 윈도우에서는 명명된 파이프와 메일슬롯이 유사한 역할을 한다. 응용 프로그램은 통신해야 하는 데이터의 양, 성능 요구사항, 프로세스 간의 관계 등을 고려하여 적절한 IPC 기법을 선택한다.

6.3. IPC 구현 예시

IPC는 다양한 방법으로 구현된다. 가장 일반적인 기법으로는 공유 메모리, 메시지 전달, 파이프, 소켓 등이 있다.

IPC 기법

통신 방식

주요 특징

일반적인 사용 예

공유 메모리

메모리 영역을 공유하여 직접 읽기/쓰기

속도가 매우 빠르지만, 개발자가 직접 동기화를 관리해야 함

대용량 데이터를 빠르게 교환해야 하는 고성능 컴퓨팅(HPC), 데이터베이스

메시지 전달 (Message Passing)

커널을 통해 메시지를 주고받음

구현이 비교적 간단하고 동기화가 내재되어 있으나, 오버헤드가 있음

마이크로서비스 아키텍처, 분산 시스템, MPI(Message Passing Interface)

파이프(Pipe)

단방향 바이트 스트림

부모-자식 프로세스 간의 순차적 통신에 주로 사용됨

쉘(Shell)에서 명령어 연결(`ls \

명명된 파이프(Named Pipe / FIFO)

파일 시스템에 이름이 있는 양방향 파이프

무관계 프로세스 간 통신 가능

로그 수집기, 클라이언트-서버 간 단순 통신

소켓(Socket)

네트워크 프로토콜을 사용한 통신

동일 머신 내 또는 네트워크를 넘어 다른 머신의 프로세스와도 통신 가능

웹 서버-브라우저, 모든 네트워크 기반 애플리케이션

구체적인 예를 들면, 공유 메모리는 /dev/shm과 같은 메모리 파일 시스템을 활용하거나, shmget(), shmat() 같은 시스템 호출을 사용하여 구현된다. 반면, 메시지 큐는 msgget(), msgsnd(), msgrcv() 시스템 호출을 통해 메시지를 보내고 받는 방식으로 작동한다. 현대 운영체제는 대부분 이러한 기법들을 제공하며, 프로그래밍 언어의 라이브러리(예: Python의 multiprocessing 모듈, Java의 java.nio 채널)를 통해 더 추상화된 형태로 사용하기도 한다.

7. 스레드 동기화

동기화는 둘 이상의 스레드가 공유 자원에 동시에 접근하거나, 실행 순서를 조정해야 할 때 발생하는 문제를 해결하기 위해 필요하다. 멀티스레딩 환경에서 여러 스레드가 동일한 메모리 영역(예: 전역 변수, 힙 데이터)을 읽고 쓰는 경우, 실행 순서에 따라 예상치 못한 결과가 발생할 수 있다. 이를 경쟁 조건이라고 한다. 동기화는 이러한 비결정적 실행을 방지하고, 스레드 간의 상호 배제와 실행 순서 제어를 보장하여 프로그램의 정확성을 유지한다.

주요 동기화 기법으로는 뮤텍스와 세마포어가 널리 사용된다. 뮤텍스는 상호 배제를 위한 잠금 장치로, 한 번에 하나의 스레드만이 임계 구역에 진입할 수 있도록 한다. 스레드는 임계 구역에 들어가기 전에 뮤텍스를 획득하고, 나온 후에 반납한다. 세마포어는 신호 메커니즘을 사용하는 동기화 도구로, 정수 값과 대기 큐를 가진다. 세마포어 값은 사용 가능한 자원의 수를 나타내며, wait()(또는 P) 연산으로 값을 감소시키고, signal()(또는 V) 연산으로 값을 증가시킨다. 세마포어는 뮤텍스처럼 상호 배제(이진 세마포어)에 사용될 수도 있고, 여러 개의 자원에 대한 접근을 제어(계수 세마포어)하는 데에도 사용될 수 있다.

동기화 기법

주요 목적

특징

뮤텍스

상호 배제

한 스레드만이 임계 구역 점유. 잠금을 소유한 스레드만이 해제 가능.

세마포어

신호 및 자원 접근 제어

정수 카운터를 기반. 자원의 개수를 관리하거나 이벤트 신호에 사용.

잘못된 동기화는 교착 상태를 유발할 수 있다. 교착 상태는 두 개 이상의 스레드가 서로 상대방이 점유한 자원을 기다리며 무한정 대기하는 상태를 말한다. 교착 상태 발생의 네 가지 필요 조건은 상호 배제, 점유와 대기, 비선점, 순환 대기이다[3]. 이를 방지하기 위해 자원 할당 순서를 정하거나, 타임아웃을 도입하거나, 교착 상태 탐지 및 회복 알고리즘을 사용하는 등의 방법이 존재한다.

7.1. 동기화의 필요성

동기화는 둘 이상의 스레드가 공유 자원에 동시에 접근하거나, 실행 순서를 조정해야 할 때 발생하는 문제를 해결하기 위해 필요하다. 공유 메모리, 파일, 데이터베이스 연결과 같은 자원을 여러 스레드가 경쟁적으로 사용하면 경쟁 조건이 발생하여 데이터의 일관성이 깨질 수 있다. 예를 들어, 한 스레드가 데이터를 읽는 도중에 다른 스레드가 그 데이터를 변경하면, 첫 번째 스레드는 예상치 못한 또는 손상된 데이터를 얻게 된다. 따라서 이러한 비정상적인 실행 결과를 방지하고 프로그램의 정확성을 보장하기 위해 동기화 메커니즘이 필수적이다.

동기화가 필요한 주요 상황은 크게 두 가지로 나눌 수 있다. 첫째는 상호 배제로, 한 번에 하나의 스레드만이 임계 구역에 진입하여 공유 자원을 사용하도록 보장하는 것이다. 둘째는 실행 순서 제어로, 특정 스레드가 다른 스레드의 작업이 끝날 때까지 기다리도록 하여 작업 간의 의존성을 관리하는 것이다. 예를 들어, 생산자 스레드가 데이터를 버퍼에 넣기 전까지 소비자 스레드가 데이터를 가져가지 못하도록 하는 것이 이에 해당한다.

동기화 기법을 적용하지 않으면 발생할 수 있는 문제는 다음과 같다.

문제점

설명

데이터 불일치

여러 스레드가 동시에 공유 변수를 수정할 때, 최종 값이 예상과 다르게 될 수 있다.

교착 상태

두 개 이상의 스레드가 서로 상대방이 점유한 자원을 무한정 기다리는 상태에 빠질 수 있다.

기아 상태

특정 스레드가 계속해서 자원을 할당받지 못하고 실행이 지연되는 상태가 될 수 있다.

따라서 뮤텍스, 세마포어, 모니터와 같은 동기화 도구를 사용하여 스레드 간의 협력적이고 안전한 실행 환경을 조성하는 것이 중요하다. 올바른 동기화는 프로그램의 신뢰성과 성능을 결정하는 핵심 요소이다.

7.2. 뮤텍스와 세마포어

뮤텍스는 상호 배제를 보장하는 동기화 도구이다. 한 번에 하나의 스레드만이 공유 자원에 접근할 수 있도록 잠금을 제공한다. 뮤텍스를 소유한 스레드만이 해당 자원을 사용할 수 있으며, 사용이 끝나면 잠금을 해제하여 다른 스레드가 접근할 수 있게 한다. 이는 주로 임계 구역을 보호하는 데 사용된다.

세마포어는 에츠허르 데이크스트라가 제안한, 더 일반화된 동기화 메커니즘이다. 세마포어는 정수 값과 대기 큐를 가지며, P 연산(wait)과 V 연산(signal)을 통해 카운트를 조절한다. 이진 세마포어는 값이 0 또는 1로, 뮤텍스와 유사하게 동작한다. 계수 세마포어는 0 이상의 값을 가져, 제한된 수의 스레드가 동시에 자원에 접근하도록 제어하는 데 사용된다[4].

두 기법의 주요 차이는 소유권 개념에 있다. 뮤텍스는 잠금을 획득한 스레드가 반드시 잠금을 해제해야 하지만, 세마포어는 한 스레드가 P 연산을 하고 다른 스레드가 V 연산을 할 수 있다. 또한 세마포어는 시스템 범위에 존재할 수 있어 프로세스 간 통신에도 사용되지만, 뮤텍스는 일반적으로 같은 프로세스 내의 스레드 사이에서만 사용된다.

특성

뮤텍스

세마포어

동작 방식

잠금/해제 (Lock/Unlock)

신호 카운트 (P/V 또는 Wait/Signal)

소유권

잠금을 획득한 스레드가 해제해야 함

소유권 개념이 없음

유형

기본적으로 이진 형태

이진 또는 계수 형태

주요 용도

임계 구역 보호

임계 구역 보호, 자원 접근 수 제한, 작업 순서 조정

적용 범위

주로 동일 프로세스 내 스레드

동일 프로세스 내 또는 프로세스 간 통신

7.3. 교착 상태(Deadlock)

교착 상태는 둘 이상의 프로세스나 스레드가 서로 상대방이 점유하고 있는 자원을 기다리며, 더 이상 진행하지 못하고 영원히 멈춰 버리는 상태이다. 이는 동기화 기법을 사용하는 다중 프로그래밍 환경에서 발생할 수 있는 심각한 문제이다.

교착 상태가 발생하기 위해서는 네 가지 필요 조건이 동시에 성립해야 한다. 이 조건들은 다음과 같다.

조건

설명

상호 배제(Mutual Exclusion)

한 번에 한 프로세스만이 특정 자원을 사용할 수 있다. 다른 프로세스는 그 자원이 해제될 때까지 기다려야 한다.

점유와 대기(Hold and Wait)

프로세스가 이미 일부 자원을 점유한 상태에서, 다른 프로세스가 점유한 추가 자원을 얻기 위해 대기한다.

비선점(No Preemption)

다른 프로세스가 점유한 자원을 강제로 빼앗을 수 없다. 자원은 점유한 프로세스가 자발적으로 해제해야 한다.

순환 대기(Circular Wait)

두 개 이상의 프로세스가 자원의 점유와 대기 상태에서 순환적인 체인을 형성한다. 예를 들어, 프로세스 P1은 P2가 점유한 자원을, P2는 P1이 점유한 자원을 기다리는 경우이다.

교착 상태를 처리하는 주요 방법은 예방, 회피, 탐지 및 복구로 나뉜다. 예방은 위의 네 가지 필요 조건 중 하나 이상을 성립하지 않도록 보장하여 교착 상태가 발생할 가능성을 근본적으로 차단한다. 회피는 은행원 알고리즘과 같이 자원 할당 상태를 사전에 분석하여 안전한 상태에서만 자원을 할당하는 방식이다. 탐지 및 복구는 주기적으로 시스템 상태를 검사하여 교착 상태가 발생했는지 확인하고, 발생한 경우 하나 이상의 프로세스를 강제 종료하거나 자원을 선점하여 상태를 해결한다. 각 방법은 성능 오버헤드와 자원 활용도 간의 트레이드오프 관계에 있다[5].

8. 프로세스 스케줄링

프로세스 스케줄링은 운영체제의 커널이 시스템 내의 여러 프로세스들 중에서 어느 프로세스에게 CPU를 할당할지 결정하는 작업이다. 이는 다중 프로그래밍 환경에서 제한된 수의 CPU 자원을 여러 프로세스가 효율적으로 공유할 수 있도록 하기 위해 필수적이다. 스케줄링의 근본적인 목적은 시스템의 성능을 최적화하고, 공정성을 유지하며, 모든 프로세스가 적절한 응답 시간을 얻을 수 있도록 하는 것이다.

주요 스케줄링 알고리즘은 크게 선점형과 비선점형으로 나뉜다. 대표적인 알고리즘으로는 다음과 같은 것들이 있다.

알고리즘

유형

주요 특징

FCFS(First-Come, First-Served)

비선점형

도착한 순서대로 처리. 간단하지만 평균 대기 시간이 길어질 수 있다.

SJF(Shortest Job First)

비선점형/선점형

실행 시간이 가장 짧은 프로세스를 먼저 처리. 평균 대기 시간을 최소화한다.

라운드 로빈(Round Robin)

선점형

각 프로세스에 고정된 시간 할당량(타임 퀀텀)을 주고 순환한다. 대화형 시스템에 적합하다.

우선순위 스케줄링(Priority Scheduling)

선점형/비선점형

각 프로세스에 우선순위를 부여하여 높은 순위의 작업을 먼저 처리한다.

다단계 큐(Multilevel Queue)

혼합형

프로세스를 특성에 따라 여러 큐로 분리하고, 각 큐마다 다른 스케줄링 정책을 적용한다.

스케줄링 알고리즘의 성능은 여러 기준으로 평가된다. 가장 일반적인 평가 기준으로는 CPU 이용률, 처리량(단위 시간당 완료된 프로세스 수), 턴어라운드 타임(작업 제출부터 완료까지의 총 소요 시간), 대기 시간(준비 큐에서 대기한 시간), 그리고 응답 시간(요청 후 첫 응답이 나올 때까지의 시간) 등이 있다. 이러한 지표들은 서로 트레이드오프 관계에 있기 때문에, 시스템의 목적(예: 일괄 처리 시스템 vs 대화형 시스템)에 따라 적절한 알고리즘을 선택해야 한다.

8.1. 스케줄링의 목적

스케줄링의 주요 목적은 프로세스나 스레드와 같은 실행 단위들에게 CPU를 효율적으로 할당하여 시스템의 전반적인 성능을 최적화하는 것이다. 이는 단일 사용자 시스템에서는 응답 시간을 줄이는 데 초점이 맞춰지지만, 다중 사용자나 다중 작업 환경에서는 공정성과 처리량 극대화가 더욱 중요해진다.

구체적인 목표는 다음과 같이 나열할 수 있다.

목표

설명

공정성

모든 프로세스가 공정하게 CPU 시간을 할당받아 특정 프로세스가 기아 상태에 빠지지 않도록 한다.

처리량 극대화

단위 시간당 완료하는 프로세스의 수를 최대화한다.

응답 시간 최소화

대화형 시스템에서 요청에 대한 첫 번째 응답이 나올 때까지의 시간을 최소화한다.

반환 시간 최소화

프로세스가 제출되어 실행을 완료할 때까지 걸리는 총 시간(대기 시간 + 실행 시간)을 최소화한다.

CPU 이용률 극대화

가능한 한 CPU를 바쁘게 유지하여 유휴 시간을 줄인다.

대기 시간 최소화

프로세스가 준비 큐에서 실행을 위해 대기하는 시간을 최소화한다.

이러한 목표들은 서로 상충되는 경우가 많아, 운영체제는 시스템의 종류(일괄 처리, 대화형, 실시간 시스템 등)와 작업 부하에 따라 적절한 스케줄링 알고리즘을 선택하여 균형을 잡는다. 예를 들어, 실시간 시스템은 데드라인을 맞추는 것이 가장 중요하지만, 일반적인 시분할 시스템은 응답 시간과 공정성을 더 중시한다.

8.2. 주요 스케줄링 알고리즘

스케줄링 알고리즘은 운영체제가 프로세스나 스레드에 CPU 자원을 할당하는 순서를 결정하는 규칙이다. 알고리즘은 시스템의 목표(처리량 극대화, 응답 시간 최소화 등)에 따라 다양하게 설계된다.

주요 알고리즘은 다음과 같이 분류할 수 있다.

알고리즘 종류

설명

특징

선입 선처리(FCFS)

도착한 순서대로 처리하는 비선점형 알고리즘이다.

구현이 간단하지만, 평균 대기 시간이 길어질 수 있다.

최단 작업 우선(SJF)

실행 시간이 가장 짧은 프로세스를 먼저 처리한다.

평균 대기 시간을 최소화하지만, 실행 시간을 정확히 예측하기 어렵다.

우선순위 스케줄링

각 프로세스에 부여된 우선순위에 따라 CPU를 할당한다.

우선순위가 낮은 프로세스는 기아 상태에 빠질 수 있다.

라운드 로빈(RR)

각 프로세스에 시간 할당량(타임 퀀텀)을 주고 순환하며 실행하는 선점형 알고리즘이다.

모든 프로세스에 공정하게 CPU 시간을 분배하여 대화형 시스템에 적합하다.

다단계 큐 스케줄링

프로세스를 특성별로 여러 큐로 분류하고, 각 큐마다 다른 스케줄링 알고리즘을 적용한다.

시스템 작업, 대화형 작업, 배치 작업 등을 구분하여 효율적으로 관리한다.

다단계 피드백 큐

프로세스가 큐 사이를 이동할 수 있는 다단계 큐의 발전된 형태이다.

CPU 버스트 시간이 긴 프로세스는 점점 낮은 우선순위 큐로 이동시키는 방식으로 동작한다.

실제 운영체제는 이러한 기본 알고리즘들을 변형하거나 조합하여 사용한다. 예를 들어, 현대의 대화형 운영체제는 라운드 로빈의 공정성과 우선순위 스케줄링의 효율성을 결합한 방식을 주로 채용한다. 알고리즘 선택은 시스템의 작업 부하와 성능 목표에 따라 결정된다.

8.3. 스케줄링 평가 기준

스케줄링 알고리즘의 성능을 평가하는 기준은 크게 시스템 관점과 사용자 관점으로 나뉜다. 시스템 관점의 기준은 프로세서나 메모리 같은 시스템 자원의 효율적인 활용도를 측정하는 반면, 사용자 관점의 기준은 개별 프로세스가 시스템에서 받는 서비스의 질을 평가한다.

주요 평가 기준은 다음과 같다.

기준

설명

평가 관점

CPU 이용률

CPU가 놀지 않고 작업을 처리하는 시간의 비율이다. 높을수록 좋다.

시스템

처리량

단위 시간당 완료된 프로세스의 수이다. 높을수록 좋다.

시스템

반환 시간

프로세스가 제출된 시점부터 실행이 완료될 때까지 걸리는 총 시간이다.

사용자

대기 시간

프로세스가 준비 큐에서 CPU를 할당받기 위해 대기한 시간의 합이다.

사용자

응답 시간

대화형 시스템에서 요청을 제출한 후 첫 번째 응답이 나올 때까지의 시간이다.

사용자

이러한 기준들은 서로 트레이드오프 관계에 있는 경우가 많다. 예를 들어, CPU 이용률과 처리량을 극대화하려면 문맥 교환을 최소화해야 하지만, 이는 응답 시간을 악화시킬 수 있다[6]. 따라서 운영체제는 시스템의 목표(예: 실시간 시스템, 일괄 처리 시스템, 대화형 시스템)에 따라 적절한 스케줄링 정책을 선택한다.

9. 실제 구현 예시

운영체제마다 프로세스와 스레드를 구현하고 관리하는 방식에 차이가 존재한다. 유닉스 및 리눅스 계열 운영체제는 전통적으로 프로세스를 가벼운 실행 단위로 취급하며, clone() 시스템 호출을 통해 스레드를 생성한다. 이는 스레드가 별도의 프로세스 제어 블록을 완전히 가지기보다는 일부 자원을 공유하는 프로세스의 변형으로 구현됨을 의미한다. 반면, 마이크로소프트 윈도우는 커널 수준에서 스레드를 명시적으로 지원하며, 각 스레드가 별도의 실행 컨텍스트를 가지지만 동일한 프로세스 주소 공간을 공유하는 모델을 채택한다.

주요 프로그래밍 언어와 라이브러리도 이러한 운영체제 차이를 추상화하여 다양한 스레딩 모델을 제공한다. 자바는 JVM이 운영체제의 네이티브 스레드와 1:1로 매핑되는 모델을 사용하여 플랫폼 독립적인 스레드 인터페이스를 제공한다. 파이썬의 경우, 공식 구현체인 CPython은 GIL로 인해 한 번에 하나의 네이티브 스레드만 파이썬 바이트코드를 실행할 수 있어 CPU 병렬성에 제약이 있지만, I/O 바운드 작업에는 효과적이다. C++의 경우, C++11 표준부터 <thread> 라이브러리를 통해 표준화된 멀티스레딩 지원을 시작했다.

아래 표는 주요 환경에서의 프로세스와 스레드 구현 특징을 비교한 것이다.

환경

프로세스 생성 기본 방식

스레드 모델

주요 특징

리눅스

fork()

커널 스레드 (NPTL 사용)

스레드를 가벼운 프로세스(LWP)로 관리.

Windows

CreateProcess()

커널 스레드

스레드 풀링 API를 포함한 풍부한 스레드 관리 기능 제공.

Java

ProcessBuilder

JVM이 관리하는 1:1 네이티브 스레드

플랫폼 독립적. 스레드 풀은 java.util.concurrent 패키지로 제공.

CPython

subprocess / os.fork()

GIL 하의 사용자 스레드 (네이티브 스레드 사용)

CPU 병렬 처리를 위해 multiprocessing 모듈을 별도로 제공.

C++ (11 이후)

플랫폼 의존적 (e.g., fork())

std::thread (일반적으로 1:1 모델)

표준 라이브러리를 통한 이식성 있는 스레드 생성 및 관리.

이러한 구현 차이는 성능, 이식성, 디버깅 복잡도에 직접적인 영향을 미친다. 예를 들어, 많은 수의 동시 연결을 처리하는 서버는 리눅스의 epoll과 같은 I/O 멀티플렉싱 기법과 경량 스레드(예: 고루틴)를 결합하는 방식으로 구현되는 경우가 많다. 따라서 특정 애플리케이션을 설계할 때는 목표 플랫폼과 언어의 실행 모델을 고려해야 한다.

9.1. 운영체제별 구현 차이

주요 운영체제는 프로세스와 스레드를 관리하는 데 있어 고유한 접근 방식을 채택한다. 유닉스 및 리눅스 계열 시스템은 전통적으로 프로세스를 가볍게 생성하는 fork 시스템 호출을 사용하며, POSIX 스레드(pthreads) 라이브러리를 통해 스레드를 지원한다. 리눅스 커널은 스레드를 다른 프로세스와 마찬가지로 태스크 구조체(task_struct)로 표현하지만, 같은 프로세스 식별자(PID)를 공유하는 방식으로 구현한다[7].

마이크로소프트 윈도우는 프로세스와 스레드를 명확히 구분하는 객체 기반 모델을 사용한다. 윈도우 커널은 각 프로세스와 스레드를 실행체 객체(Executive Object)로 관리하며, 스레드 생성은 CreateThread API를 통해 이루어진다. 윈도우의 스레드는 기본적으로 해당 프로세스의 가상 주소 공간과 자원을 공유하지만, 윈도우 API는 프로세스 간 통신을 위한 다양한 메커니즘(파이프, 메일슬롯, 공유 메모리 등)을 제공한다.

macOS와 iOS의 기반인 다윈(Darwin) 커널은 마하 커널의 영향을 받아 태스크와 스레드를 분리한 모델을 사용한다. 여기서 태스크는 자원 컨테이너이며, 스레드는 실행 흐름의 단위이다. 애플의 그랜드 센트럴 디스패치(GCD) 기술은 이 시스템 위에서 동작하며, 스레드 풀을 효율적으로 관리하여 개발자가 저수준의 스레드 생성보다는 작업(task) 단위로 병렬 처리를 설계할 수 있게 한다.

운영체제

프로세스 생성 기본 방식

스레드 모델/API

주요 특징

리눅스/유닉스

fork()

POSIX 스레드(pthreads)

스레드를 경량 프로세스로 구현, clone() 시스템 호출 사용

마이크로소프트 윈도우

CreateProcess()

윈도우 API(CreateThread)

커널 수준의 스레드 객체, 풍부한 IPC 메커니즘

macOS/iOS

posix_spawn() / fork()

POSIX 스레드 / NSThread / GCD

마하 커널 기반의 태스크-스레드 분리 모델, GCD 제공

이러한 구현 차이는 성능, 이식성, 프로그래밍 모델에 직접적인 영향을 미친다. 예를 들어, 리눅스의 fork()는 쓰기 시 복사(Copy-on-Write) 기법으로 효율적이지만, 윈도우의 프로세스 생성은 일반적으로 더 무겁다. 반면, 현대 운영체제들은 대부분 선점형 멀티태스킹과 멀티스레딩을 지원하며, 하이퍼스레딩이나 멀티코어 프로세서를 효율적으로 활용하기 위해 내부 스케줄러를 지속적으로 발전시키고 있다.

9.2. 프로그래밍 언어별 지원 방식

프로세스와 스레드를 생성하고 관리하는 방식은 프로그래밍 언어와 그 언어의 런타임 환경에 따라 크게 달라진다. 일부 언어는 운영체제의 네이티브 스레드를 직접적으로 지원하는 반면, 다른 언어는 가상 머신이나 런타임 라이브러리 수준에서 추상화된 경량 스레드 모델을 제공하기도 한다.

언어 / 환경

주요 스레드 모델

특징 및 구현 방식

C / C++

네이티브 스레드 ([[POSIX 스레드

Pthreads]], Windows Threads)

Java

네이티브 스레드 기반의 가상 스레드 ([[Java 가상 머신

JVM]] 스레드)

Python (CPython)

[[전역 인터프리터 락

GIL]] 하의 네이티브 스레드

Go

고루틴 (Goroutine)

언어 자체에 내장된 경량 스레드인 고루틴을 제공한다. 고루틴은 Go 런타임에 의해 관리되며, 적은 수의 운영체제 스레드 위에서 다중화되어 실행되어 생성 및 문맥 교환 비용이 매우 낮다. 채널을 통한 통신이 기본 동기화 메커니즘이다.

JavaScript (브라우저/Node.js)

단일 스레드 이벤트 루프 + 웹 워커/워커 스레드

기본 실행 모델은 단일 스레드 이벤트 루프이다. 병렬 처리를 위해 브라우저 환경에서는 웹 워커, Node.js에서는 워커 스레드 API를 사용하여 별도의 스레드(또는 프로세스)에서 스크립트를 실행할 수 있다.

이러한 차이는 언어의 설계 철학과 주요 사용 영역에 기인한다. 시스템 프로그래밍 언어인 C/C++은 하드웨어에 가까운 저수준 제어를 제공하는 반면, Go나 최신 Java는 높은 수준의 동시성 추상화를 지향한다. Python의 GIL은 구현의 단순성과 안정성에서 비롯된 역사적 유산이다. 따라서 애플리케이션의 요구사항에 맞는 동시성 모델을 지원하는 언어를 선택하거나, 해당 언어의 패러다임 내에서 효과적인 병렬 처리 방식을 적용하는 것이 중요하다.

10. 관련 문서

  • Wikipedia - 프로세스 (컴퓨터 과학)

  • Wikipedia - 스레드 (컴퓨팅)

  • Wikipedia - Process (computing)

  • Wikipedia - Thread (computing)

  • GeeksforGeeks - Difference between Process and Thread

  • IBM Documentation - What is a process?

  • Microsoft Learn - Processes and Threads

  • Oracle - Processes and Threads

리비전 정보

버전r1
수정일2026.02.13 07:12
편집자unisquads
편집 요약AI 자동 생성