본문으로 이동
  • 현재 모든 문서는 작성 중입니다. 보시는 데 불편함이 있더라도 양해 부탁드립니다.

운영체제 기본/프로세스와 스레드

~ldmsys
관리자 (토론 | 기여)님의 2026년 10월 31일 (토) 07:00 판 (총론 재작성: 자원과 실행 문맥의 분리, 격리·통신 비용 및 스케줄링 trade-off)

목차 · 이전: 보호와 시스템 호출 · 다음: 동시성

컴퓨터에서 여러 작업을 진행하려면 두 가지를 정해야 한다. 작업마다 어떤 자원을 따로 줄 것인지, CPU에서 어떤 실행 흐름을 언제 진행할 것인지다. 프로세스는 주소 공간과 자원, 보호 경계를 묶는 단위이고, 스레드는 그 안에서 명령을 실행하는 흐름이다.

이 구분을 통해 자원의 소유와 실행 순서를 별도로 관리할 수 있다. 프로그램 하나를 프로세스 하나, 스레드 하나로 실행할 수도 있고, 같은 자원을 여러 스레드가 공유하게 할 수도 있다.

실행 파일만으로는 실행 상태를 표현할 수 없다

실행 파일에는 코드와 초기 데이터가 있다. 실행 중에는 다음 명령의 위치, 레지스터 값, 함수 호출 스택, 동적으로 할당한 메모리, 열린 입출력 대상 등도 필요하다. 같은 실행 파일을 두 번 실행하더라도 이 상태는 다를 수 있다.

운영체제는 실행을 중단했다가 다시 이어갈 수 있도록 실행 문맥을 관리한다. 스레드마다 레지스터와 스택이 필요한 이유도 여기에 있다. 같은 함수를 실행하더라도 각 호출의 인자와 지역 변수, 돌아갈 위치는 달라야 한다.

실행 문맥을 새로 만드는 일과 실행할 프로그램을 바꾸는 일도 구분된다. Unix 계열에서는 프로세스를 생성하는 연산과 기존 프로세스의 실행 이미지를 교체하는 연산이 분리되어 있다. 생성과 실행을 나누면 새 프로그램을 시작하기 전에 입출력 연결이나 실행 환경을 구성할 수 있다. 대신 어떤 상태를 상속하고 어떤 상태를 초기화할지 명확한 규칙이 필요하다. fork(2) · execve(2)

격리를 늘리면 전달 비용이 생긴다

여러 요청을 처리하는 서버를 생각해 보자. 요청별 작업을 서로 다른 주소 공간에 두면 한 작업의 잘못된 메모리 쓰기가 다른 작업의 사적인 메모리를 직접 덮어쓰지 않는다. 요청 하나의 실패가 다른 요청으로 번지는 범위를 줄일 수 있다.

대신 결과나 공통 데이터를 주고받을 통신 경로가 필요하다. 메시지에 담을 데이터 표현을 정해야 하고, 구현에 따라 복사와 직렬화, 커널 경계 통과 비용이 발생한다. 공유 메모리로 복사를 줄일 수 있지만, 그 영역에는 다시 접근 규칙과 동기화가 필요하다.

같은 프로세스 안에서 스레드를 늘리면 주소 공간과 열린 파일 등을 공유하므로 포인터로 같은 객체를 다룰 수 있다. 연결과 전달이 간단해지는 대신, 잘못된 쓰기와 공유 상태의 오염도 다른 스레드에 영향을 준다. 스레드별 스택은 독립적인 실행 상태이지, 서로 접근할 수 없는 보호 경계는 아니다. pthreads(7)

따라서 프로세스와 스레드의 선택은 생성 비용만으로 결정되지 않는다. 공유할 데이터의 양, 장애를 격리할 범위, 통신 비용, 동기화 복잡도를 함께 고려해야 한다. 별도 프로세스도 같은 파일이나 공유 메모리를 변경한다면 경쟁 문제가 생긴다.

CPU를 나누는 방법

실행 가능한 흐름이 CPU보다 많으면 순서를 정해야 한다. 운영체제는 한 스레드의 문맥을 보관하고 다른 스레드의 문맥을 복원해 실행을 넘긴다. 이것이 문맥 교환이다. 논리 CPU 하나에서는 여러 흐름이 번갈아 진행하고, 여러 논리 CPU에서는 병렬 실행도 가능하다.

실행 중인 작업이 자발적으로 CPU를 내놓게 하는 방식은 전환 지점이 명확하다. 그러나 오래 실행하거나 양보하지 않는 작업이 다른 작업을 지연시킬 수 있다. 선점은 운영체제가 실행을 중단시켜 다른 작업에 기회를 주는 방식이다. 응답성과 공정성을 확보하는 데 유리하지만, 프로그램은 예상하지 못한 지점에서 실행 순서가 바뀔 수 있음을 전제로 해야 한다.

전환 간격을 짧게 하면 대기 중인 작업이 빨리 기회를 얻을 수 있다. 반면 문맥 저장·복원 비용이 늘고, 캐시와 주소 변환 캐시를 다시 채우는 비용이 발생할 수 있다. 길게 실행시키면 이런 비용을 줄일 여지가 있지만 짧은 작업의 응답 시간이 길어질 수 있다.

처리량, 응답 시간, 공정성, 마감 시간 준수는 서로 다른 목표다. 대화형 작업과 일괄 계산, 실시간 작업에 같은 선택이 최선일 수는 없다. sched(7)

기다리는 작업에 CPU를 주지 않는 이유

네트워크 응답이 도착하지 않았거나 필요한 입출력이 끝나지 않았다면 CPU를 더 준다고 작업이 진행되지는 않는다. 이때 실행 흐름을 대기 상태로 두고, 진행할 수 있는 다른 작업에 CPU를 주는 편이 자원 사용에 유리하다.

상태 전이는 다음처럼 구분할 수 있다.

실행 가능 ── 선택 ──> 실행 중
    ↑                  │
    └──── 선점 ────────┤
                       │ 입출력·사건 대기
                       v
                     대기 중
                       │ 조건 충족
                       └────────> 실행 가능

조건이 충족되어 깨어났다는 사실은 즉시 CPU를 얻었다는 뜻이 아니다. 다시 실행 가능한 후보가 되었으며, 실제 실행 시점은 스케줄링에 달려 있다. 따라서 작업의 완료 시간에는 계산 시간뿐 아니라 실행 기회를 기다리는 시간과 외부 조건을 기다리는 시간도 포함된다.

대기를 사용하는 설계는 다른 작업에 CPU를 돌려줄 수 있지만, 멈추고 깨우는 처리와 스케줄링 비용이 있다. 아주 짧은 대기라면 잠시 상태를 반복 확인하는 편이 유리할 수도 있다. 이 선택과 공유 상태의 정확성 문제는 동시성에서 다룬다.

관련 각론

  • PID 1 생성: 기존 부트 태스크와 새 실행 문맥이 갈라지는 과정.