운영체제 용어 사전
프로세스

스레드

같은 주소 공간을 공유하는 실행 흐름. 전환이 싸지만 공유하기 때문에 동기화가 필요하다.

프로세스 안의 실행 흐름. 같은 주소 공간을 공유한다.

무엇을 나누고 무엇을 따로 갖나

  • 공유하는 것 — 코드 · 데이터 · 힙 · 열린 파일 · 시그널 핸들러

  • 따로 갖는 것 — 스택 · 레지스터 · 프로그램 카운터 · 스레드 ID

  • 힙을 공유한다 = 객체를 그냥 넘길 수 있다 (장점)

    • = 동시에 건드리면 깨진다 (단점)

전환이 왜 싼가

프로세스 전환

  • 레지스터 저장·복원 + 페이지 테이블 교체 + TLB 플러시
  • 캐시·TLB 가 통째로 식는다 (가장 비싼 부분)

스레드 전환

  • 같은 주소 공간이라 페이지 테이블 교체가 없다
  • TLB 를 그대로 쓴다 → 훨씬 싸다

"스레드가 가볍다"의 실체는 주소 공간 전환이 없다는 것이다.

누가 스케줄하나

커널 스레드 (1:1)

  • 커널이 안다 → 멀티코어에 진짜로 분산된다
  • 하나가 블로킹돼도 나머지는 돈다
  • 대신 생성·전환에 커널이 개입해 비싸다

유저 스레드 (N:1)

  • 커널은 프로세스 하나로만 본다 → 라이브러리가 스케줄한다
  • 전환이 매우 싸다 (커널 개입 없음)
  • 치명적 약점: 하나가 블로킹되면 전부 멈춘다
    • 멀티코어를 못 쓴다

M:N (하이브리드)

  • 유저 스레드 M 개를 커널 스레드 N 개에 매핑한다
  • 둘의 장점을 노리지만 구현이 복잡하다
ps -eLf | head             # 스레드까지 보기 (LWP 열)
cat /proc/<pid>/status | grep Threads
top -H -p <pid>            # 스레드별 CPU

얼마나 만들 수 있나

스레드 하나 = 스택 (기본 8MB 예약, 실제 사용분만 물리 할당)

    • 커널의 관리 구조

수천 개면 메모리와 스케줄링이 부담이 된다

  • 그래서 "연결마다 스레드" 모델이 대규모 동시성에서 무너진다
ulimit -s                              # 스레드 스택 크기
cat /proc/sys/kernel/threads-max       # 시스템 전체 상한

면접 함정

  • "스레드가 프로세스보다 항상 낫다" → 하나가 죽으면 프로세스 전체가 죽는다. 격리가 필요하면 프로세스다.
  • "스레드는 스택도 공유한다" → 스택은 각자 갖는다. 그래서 지역 변수는 안전하다.

스레드가 많을 때 무엇이 문제인가

  • 메모리 — 스택 예약 (기본 8MB 가상, 실사용은 적지만 주소 공간을 먹는다)
    • 32비트에서는 이것만으로 한계에 닿는다
  • 스케줄링 준비 큐가 길어지고 컨텍스트 스위치가 폭증한다
  • 캐시 — 각 스레드의 작업 데이터가 캐시를 밀어낸다
ulimit -s 512                    # 스택을 줄여 더 많이 만들 수 있게 (KB 단위)
cat /proc/<pid>/status | grep -E 'Threads|VmRSS'

스레드 안전이란

여러 스레드가 동시에 호출해도 올바르게 동작하는 것

안전하게 만드는 세 가지

  • ① 공유하지 않는다 — 스레드 로컬 저장소 · 지역 변수

  • ② 공유하되 안 바꾼다 — 불변 데이터

  • ③ 공유하고 바꾸되 동기화한다 — 락 · 원자 연산

  • ① 이 가장 싸고 ③이 가장 비싸다. 가능하면 위쪽을 택한다

재진입성

시그널 핸들러 안에서는 아무 함수나 부르면 안 된다
  → 그 함수가 실행 중이던 걸 중단하고 들어온 것일 수 있다
  → malloc · printf 는 내부 락을 쓰므로 데드락이 날 수 있다
  → async-signal-safe 목록에 있는 함수만 쓴다 (write · _exit 등)

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 스레드 — 공유·전환 비용·유저/커널·가상 스레드