[Operating System] Process & Thread

이재·2025년 12월 27일
post-thumbnail

Process & Thread

프로세스의 메모리 구조 (User 영역 vs Kernel 영역)

커널 영역 – PCB(Process Control Block)

운영체제가 프로세스를 관리하기 위해 유지하는 핵심 정보.

PCB에는 다음 정보들이 저장된다.

  • PID(프로세스 ID)
  • 프로세스 상태 (준비/실행/대기/종료 등)
  • 레지스터 값(문맥 저장)
  • 스케줄링 우선순위
  • 메모리 정보 (어디에 로드되었는지)
  • 열린 파일, 사용 중인 I/O 장치 정보

운영체제는 모든 PCB를 프로세스 테이블에 보관하여 관리한다.

사용자 영역 – 프로세스 실행 코드가 올라가는 부분

코드 영역 (Text Segment)

  • 실행할 기계어(명령어)가 저장됨
  • 읽기 전용
  • 실행 도중 크기 변하지 않음 → 정적 영역

데이터 영역 (Data Segment)

  • 초기값이 있는 전역 변수, static 변수 저장
  • 프로그램 종료 전까지 유지
  • 정적 할당 영역

BSS 영역

  • 초기값이 없는 전역/정적 변수 저장
  • 실행 시 0으로 초기화됨
  • 데이터 영역과 동일한 생명주기

힙 영역 (Heap)

  • 동적 메모리 (new / malloc 등)
  • 개발자가 직접 할당/해제해야 함
  • 해제하지 않으면 → 메모리 누수(Memory Leak)
  • 일부 언어는 가비지 컬렉터(GC)가 자동 처리

스택 영역 (Stack)

  • 함수 호출 정보, 지역 변수, 매개변수 저장
  • 스택 프레임(Stack Frame) 형태로 쌓임
  • 재귀 호출 시 깊어짐
  • 스택 오버플로우 발생 가능

스택에는 함수 호출 기록인 스택 트레이스가 그대로 나타나기 때문에

디버깅 시 에러 위치 분석하는 데 매우 유용하다.

PCB와 문맥 교환(Context Switching)

운영체제는 여러 프로세스를 번갈아 실행하기 위해 필요한 순간마다

현재 작업 상태(레지스터, 프로그램 카운터, 스택 등)를 문맥(Context)으로 저장한다.

문맥 교환이 일어나는 순간

  • 타이머 인터럽트(time slice 종료)
  • I/O 요청으로 블록 상태 진입
  • 더 높은 우선순위 프로세스 등장

문맥 교환 비용이 큰 이유

  • 레지스터, 캐시, 메모리 정보 등을 백업해야 함
  • 캐시 미스(Cache Miss) 증가 → 속도 저하
  • 너무 잦으면 CPU 시간 상당수가 교환하다 낭비됨

그래서 OS는 문맥 교환 횟수를 최소화하도록 설계됨.

프로세스의 상태 변화

프로세스는 실행 과정에서 다음 상태를 순환한다.

생성 상태(New)

  • 메모리에 적재되어 PCB를 할당받은 상태

준비 상태(Ready)

  • CPU만 받으면 바로 실행 가능
  • 스케줄러가 선택하면 실행 상태가 됨 (디스패치)

실행 상태(Running)

  • CPU를 사용 중
  • 할당 시간이 끝나면 → 준비 상태
  • I/O 요청을 하면 → 대기 상태

대기 상태(Blocked)

  • 입출력 완료 등 특정 이벤트를 기다리는 상태
  • 조건 충족 시 다시 준비 상태로 이동

종료 상태(Terminated)

  • 프로세스 실행 완료
  • PCB 제거 후 자원 해제
  • 비정상 종료 시 PCB가 남으면 → 좀비 프로세스(Zombie)

블로킹 I/O와 논블로킹 I/O

블로킹 I/O

입출력 완료까지 프로세스가 대기 상태로 멈춤

논블로킹 I/O

입출력 요청만 하고 즉시 다음 명령 실행

→ 결과는 콜백/이벤트/폴링 등으로 나중에 확인

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

같은 프로그램을 동시에 여러 흐름으로 실행하는 방법은 두 가지다.

멀티프로세스(Multi-Process)

  • 프로세스 여러 개 실행
  • 각 프로세스는 메모리 공간 완전 분리
  • 한 프로세스가 죽어도 다른 프로세스는 영향 X
  • 크롬 브라우저 탭 구조가 대표적 사례
  • 안정성 ↑ / 자원 사용 ↑(메모리 많이 먹음)

멀티스레드(Multi-Thread)

  • 하나의 프로세스 내부에서 여러 실행 흐름
  • 스레드들은 다음을 공유함:
    • 코드 영역
    • 데이터 영역
    • 힙 영역
    • 열린 파일 등
  • 스레드마다 개별적으로 가진 것:
    • 스택
    • 레지스터
    • 프로그램 카운터

장단점

✔ 메모리 효율 높음

✔ 빠른 통신/협업 가능 (공유 자원 기반)

✘ 한 스레드가 죽으면 프로세스 전체가 죽을 위험

✘ 공유 자원 때문에 동기화, 레이스 컨디션 문제가 필수 고려 요소

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

서로 자원을 공유하지 않는 프로세스끼리 데이터를 주고받는 기술.

공유 메모리(Shared Memory)

  • 프로세스가 동일한 메모리 공간을 공유
  • 속도 가장 빠름
  • 커널 개입 ↓
  • 하지만 동기화 문제(경쟁 조건) 필수 해결 필요

메시지 전달(Message Passing)

  • 데이터를 메시지 형태로 주고받음
  • 커널이 중재함
  • 속도는 느리지만 안정적

대표 방식

  • 파이프 (익명 파이프, 지명 파이프)
  • 시그널 (비동기 신호)
  • 소켓 (네트워크 통신)
  • RPC (원격 프로시저 호출)

파이프

  • 하나의 방향으로만 흐름
  • FIFO(선입선출)
  • 부모–자식 프로세스 간 가장 흔함
  • named pipe(FIFO)는 양방향 가능 + 임의 프로세스 간 가능

시그널

  • 프로세스에 특정 이벤트 전달
  • 예: SIGINT(Ctrl+C), SIGKILL, SIGCHLD
  • 시그널 핸들러 정의 가능

RPC

  • 원격 프로세스의 함수를 직접 호출하는 방식
  • gRPC가 대표적
  • 서버 간 통신에서 많이 사용

동기화와 교착 상태

임계 구역과 레이스 컨디션

공유 자원(Shared Resource)

  • 두 개 이상의 프로세스/스레드가 동시에 접근하려는 자원
  • ex) 전역 변수, 파일, 메모리, I/O 장치

임계 구역(Critical Section)

  • 동시에 실행되면 문제가 발생하는 코드 영역

예시) 공유 파일 수정

두 스레드 A/B가 동시에 같은 파일에 “thread A”, “thread B”를 추가한다고 하자.

문맥 교환이 다음처럼 일어나면:

A: 파일 읽기 → 쓰기 대기
B: 파일 읽기 → 쓰기 → 저장
A: 쓰기 → 저장

A의 변경 사항이 사라질 수도 있다.

이처럼 실행 순서에 따라 결과가 달라지는 문제레이스 컨디션(Race Condition)이라 부른다.

동기화(Synchronization)의 목적

동기화는 두 가지 성질을 만족시키는 것이 목표다.

실행 순서 제어

  • A가 끝난 뒤에 B 실행 같은 순서 강제

상호 배제(Mutual Exclusion)

  • 공유 자원에는 한 번에 1개의 프로세스/스레드만 접근

동기화 기법

뮤텍스(Mutex Lock)

특징

  • 한 번에 1개만 들어갈 수 있는 방
  • 개념상 자물쇠(lock)
  • lock.acquire() → 임계구역 → lock.release()

역할

  • 상호 배제 보장
  • 레이스 컨디션 방지

단점

  • 공유 자원이 여러 개일 때 확장성이 떨어짐

세마포어(Semaphore)

뮤텍스의 확장판

특징

  • 한 번에 여러 개 들어갈 수 있는 방
  • 내부에 정수 값 S를 가짐
  • 공유 자원이 N개라면 S=N으로 설정

동작

  • wait(): S– (S<0이면 대기)
  • signal(): S++ (대기 중인 프로세스 깨움)

예시

자원 2개 / 프로세스 A,B,C

조건 변수(Condition Variable)

목적

  • 실행 순서를 제어하기 위한 도구
  • 특정 조건이 충족되기 전까지 스레드를 일시 중단(wait)
  • 조건 충족 시 signal로 깨움

형태

cv.wait()    // 조건 충족 전 대기
cv.signal()  // 조건 충족된 스레드 재개

언제 쓰는가?

  • A 스레드는 B 스레드가 값을 준비할 때까지 기다려야 할 때
  • 생산자-소비자 문제

모니터(Monitor)

모니터 = 뮤텍스 + 조건변수 패키지

  • 자원을 안전하게 보호해주는 구조
  • 한 번에 하나의 스레드만 모니터 내부 진입 가능
  • 내부에서 조건변수를 함께 사용하여 순서 제어도 해결 가능

대표 예: Java synchronized

public synchronized void example() {
    …
}

스레드 안전(Thread Safety)

멀티스레드 환경에서 특정 코드/객체가 레이스 컨디션 없이 잘 작동하는 상태.

예시

  • Vector → 스레드 안전 (synchronized 사용)
  • ArrayList스레드 안전 아님

교착 상태(Deadlock)

정의

여러 프로세스가 서로가 가진 자원을 기다리며 영원히 진행되지 않는 상태

교착 상태 발생 조건 (4가지)

4가지 조건이 모두 만족해야 교착 상태가 발생한다.

상호 배제

자원은 한 번에 하나만 사용 가능

점유와 대기

어떤 자원을 가진 상태로 다른 자원을 요청하며 대기

비선점

다른 프로세스에서 자원을 강제로 빼앗을 수 없음

원형 대기

프로세스들이 원형으로 서로의 자원을 기다림

교착 상태 해결 방법

예방(Prevention)

4가지 발생 조건 중 하나라도 깨뜨리는 방식.

예시

  • 자원을 한 번에 모두 요청하도록 강제 → 점유와 대기 제거
  • 자원 번호를 매겨 오름차순으로만 요청하도록 제한 → 원형 대기 제거

회피(Avoidance)

  • 위험한 상태가 되지 않도록 조심해서 자원 할당
  • 대표 알고리즘: 은행원 알고리즘(Banker's Algorithm)

검출 후 회복(Detection & Recovery)

이미 교착 상태가 발생한 뒤 해결하는 방식

방법

  • 교착 상태 프로세스 강제 종료
  • 다른 프로세스의 자원 강제로 회수(선점)
profile
고민을 좋아하는 개발자

0개의 댓글