Skip to Content
Operating System프로세스·스레드와 동기화

프로세스·스레드와 동기화 (OS 기본기)

만화로 보는 요약 — 먼저 읽어보세요

만화로 보는 요약 — 먼저 읽어보세요

프로세스/스레드가 뭐냐 → 멀티스레드는 어떻게 도냐 → 그러면 공유 자원은 어떻게 되냐 → 그걸 뮤텍스/세마포어로 어떻게 지키냐.

면접 실전 질문: ① 프로세스 vs 스레드 ② 멀티스레드 동작 방식 ③ 공유 자원 선점 ④ 뮤텍스락 vs 세마포어


1. 프로세스 vs 스레드

프로세스는 실행 중인 프로그램. OS로부터 독립된 메모리 공간(코드·데이터·힙·스택)과 자원을 할당받는 실행 단위. 스레드는 프로세스 안에서 실제로 CPU가 실행하는 흐름 단위. 한 프로세스는 1개 이상의 스레드를 가진다.

구분프로세스스레드
메모리각자 독립된 공간프로세스 내에서 공유 (코드·데이터·힙)
고유 소유전체 메모리·자원스택·레지스터·PC만 각자 소유
통신IPC 필요 (파이프, 소켓, 공유메모리 등) — 비쌈공유 메모리로 직접 통신 — 쌈
전환 비용큼 (메모리 맵·캐시 교체 = context switch)작음 (공유 자원 유지)
안정성한 프로세스가 죽어도 다른 프로세스 영향 없음한 스레드가 죽으면 프로세스 전체가 위험

한 줄 요약: 프로세스는 자원 할당의 단위(격리), 스레드는 실행/스케줄링의 단위(공유). 스레드는 힙·데이터를 공유하고 스택만 따로 갖는다.


2. 멀티스레드 동작 방식

한 프로세스가 여러 스레드로 작업을 나눠 처리하는 방식. 스레드끼리 코드·데이터·힙을 공유하므로 통신·전환 비용이 싸다.

  • 동시성(Concurrency): 코어 1개에서도 OS 스케줄러가 스레드를 아주 짧게 번갈아 실행(time slicing)해 “동시에 도는 것처럼” 보이게 함.
  • 병렬성(Parallelism): 코어가 여러 개면 스레드가 진짜 동시에 다른 코어에서 실행됨.
  • 컨텍스트 스위칭: 스케줄러가 스레드를 바꿀 때 현재 스레드의 레지스터·PC·스택 포인터를 저장하고 다음 스레드 것을 복원. 프로세스 전환보다 저렴하지만 공짜는 아님.

왜 쓰나: I/O 대기 시간 동안 다른 작업 처리(응답성↑), 멀티코어 활용(처리량↑). 대가: 공유 자원 접근이 겹치면 아래 3번의 문제가 터진다.


3. 공유 자원 선점 (경쟁 조건과 임계 영역)

여러 스레드가 같은 공유 자원(변수·파일·DB 등)에 동시에 접근하고, 그중 하나라도 쓰기(write)를 하면 실행 순서에 따라 결과가 달라진다.

  • 경쟁 조건(Race Condition): 실행 타이밍/순서에 따라 결과가 비결정적으로 바뀌는 상태.
  • 임계 영역(Critical Section): 공유 자원에 접근하는 코드 구간. 한 번에 한 스레드만 들어가야 함.
// count++ 는 원자적(atomic)이지 않다: read → +1 → write 3단계 // 두 스레드가 동시에 read 하면 둘 다 같은 값을 읽고 하나의 증가가 유실됨(lost update) int count = 0; void increment() { count++; } // 스레드 2개가 1000번씩 → 기대 2000, 실제 < 2000

해결의 핵심 = 상호 배제(Mutual Exclusion): 임계 영역을 한 번에 한 스레드만 실행하도록 잠근다. 좋은 동기화는 3가지를 만족해야 함: 상호 배제 / 진행(Progress) / 한정 대기(Bounded Waiting). 이걸 구현하는 도구가 4번의 뮤텍스·세마포어.

⚠️ 참고: DB 트랜잭션 격리수준도 “격리수준은 lost update를 못 막는다”는 같은 함정이 있다 — 애플리케이션 스레드 레벨 경쟁과 DB 레벨 경쟁은 층은 다르지만 문제 구조가 동일. (see: 트랜잭션 격리수준)


4. 뮤텍스(Mutex) vs 세마포어(Semaphore)

둘 다 공유 자원을 보호하는 동기화 도구지만, 허용하는 동시 접근 수소유권 개념이 다르다.

구분뮤텍스 (Mutex)세마포어 (Semaphore)
개념한 번에 1개 스레드만 (Lock/Unlock)카운터 N개까지 동시 접근 허용
동시 접근 수1 (상호 배제)N (자원 개수만큼)
소유권있음 — 잠근 스레드만 풀 수 있음없음 — 아무 스레드나 signal 가능
0 / 1 (binary)0 ~ N 정수 카운터
비유화장실 1칸 + 열쇠 1개주차장 N면 + 남은 자리 표시판
  • 뮤텍스: 오직 “하나만 들어가라”가 필요할 때. 락을 획득한 스레드가 반드시 해제해야 함(소유권).
  • 세마포어: “동시에 최대 N개까지 허용”이 필요할 때 (예: DB 커넥션 풀 10개, 다운로드 동시 3개 제한). acquire()로 카운터 감소, release()로 증가.
  • **이진 세마포어(Binary Semaphore)**는 값이 0/1이라 뮤텍스와 비슷해 보이지만, 소유권이 없다는 점이 결정적 차이. 세마포어는 상호 배제뿐 아니라 스레드 간 순서 제어(signaling) 에도 쓰인다.
// 세마포어: 동시 3개까지만 다운로드 허용 Semaphore sem = new Semaphore(3); void download() throws InterruptedException { sem.acquire(); // 자리 없으면 대기 try { doDownload(); } finally { sem.release(); } }

Java의 SemaphoreJava 도메인에서 다른 synchronizer(CountDownLatch, CyclicBarrier)와 함께 심화 예정.

한 줄 요약: 뮤텍스는 “1개 + 소유권 있는 락”, 세마포어는 “N개 카운터 + 소유권 없는 신호”. “화장실 1칸 열쇠(뮤텍스) vs 주차장 N면 표시판(세마포어)“로 기억.


요약

  1. 프로세스는 격리, 스레드는 공유 — 프로세스는 독립 메모리를 받는 자원 단위, 스레드는 힙·데이터를 공유하고 스택만 따로 갖는 실행 단위.
  2. 멀티스레드는 공유로 싸게 병렬/동시 처리 — 대신 공유 자원이 겹치면 경쟁 조건이 발생.
  3. 경쟁 조건은 임계 영역을 상호 배제로 막는다 — 한 번에 한 스레드만 들어가게.
  4. 뮤텍스 = 1개+소유권, 세마포어 = N개+무소유권 카운터.
Last updated on