현대의 컴퓨터 시스템은 동시에 수십, 수백 개의 프로그램을 실행하는 것처럼 보이지만 실제로는 하나의 중앙처리장치가 정교한 시간 분할과 자원 관리를 통해 이러한 병행성을 구현한다. 이 병행성을 가능하게 하는 핵심 개념이 바로 프로세스와 스레드이다. 프로세스와 스레드는 운영체제 이론의 근간을 이루는 개념이면서 동시에 실제 애플리케이션의 성능과 안정성에 직접적인 영향을 미치는 실무적 요소이기도 하다. 이 글에서는 프로세스의 정의와 상태 전이, 프로세스의 메모리 구조, 스레드의 개념과 종류, 프로세스와 스레드의 차이, 그리고 이들을 관리하는 운영체제 내부의 자료구조와 스케줄링 원리까지 체계적으로 살펴본다.

▍ 프로세스의 정의와 프로그램과의 차이
프로그램은 디스크에 저장되어 있는 정적인 명령어의 집합이다. 이는 실행되기 전까지는 단순한 파일에 불과하며 어떠한 자원도 점유하지 않는다. 반면 프로세스는 이 프로그램이 메모리에 적재되어 운영체제로부터 실행에 필요한 자원을 할당받아 실제로 동작하고 있는 동적인 상태의 개체를 의미한다. 하나의 프로그램은 여러 번 실행될 수 있으며, 이 경우 각각의 실행은 서로 다른 프로세스로 취급되어 독립적인 메모리 공간과 자원을 할당받는다.
운영체제는 각 프로세스를 관리하기 위해 프로세스 제어 블록(PCB, Process Control Block)이라는 자료구조를 커널 내부에 유지한다. PCB에는 프로세스 식별자, 프로세스 상태, 프로그램 카운터, CPU 레지스터 값, 메모리 관리 정보, 입출력 상태 정보, 계정 정보 등이 저장된다. 운영체제는 프로세스 사이를 전환할 때 이 PCB를 참조하여 이전에 실행되던 프로세스의 실행 문맥을 저장하고 다음에 실행할 프로세스의 문맥을 복원한다.
▍ 프로세스의 상태와 상태 전이 과정
프로세스는 생성된 순간부터 종료될 때까지 여러 상태를 거치며 전이한다. 운영체제마다 세부적으로 관리하는 상태의 종류는 다르지만 일반적으로 다음과 같은 다섯 가지 상태로 구분하는 것이 널리 통용되는 방식이다.
생성 상태는 프로세스가 이제 막 메모리에 적재되어 PCB를 할당받은 초기 단계를 말한다. 준비 상태는 프로세스가 실행에 필요한 모든 자원을 갖추고 CPU 할당만을 기다리고 있는 상태이며, 실제로 여러 프로세스가 준비 큐에 대기하며 스케줄러의 선택을 기다리게 된다. 실행 상태는 프로세스가 실제로 CPU를 점유하여 명령어를 처리하고 있는 상태를 가리키며, 단일 코어 환경에서는 특정 시점에 오직 하나의 프로세스만이 이 상태에 놓일 수 있다.
실행 중이던 프로세스가 입출력 장치에 대한 요청을 수행하거나 특정 이벤트의 발생을 기다려야 하는 경우에는 대기 상태로 전환된다. 입출력 장치는 CPU에 비해 처리 속도가 현저히 느리기 때문에, 프로세스를 대기 상태로 두고 그 사이 다른 프로세스에 CPU를 할당하는 방식은 시스템 전체의 처리율을 높이는 데 기여한다. 대기 중이던 입출력 작업이 완료되면 장치 컨트롤러가 인터럽트를 발생시키고, 이를 받은 운영체제는 해당 프로세스를 다시 준비 상태로 옮긴다. 마지막으로 프로세스가 모든 작업을 마치거나 강제로 종료되면 종료 상태에 도달하며, 운영체제는 해당 프로세스에 할당했던 PCB와 메모리 공간을 회수한다.
실행 상태에 있던 프로세스가 준비 상태로 돌아가는 경우도 존재하는데, 이는 타이머 인터럽트로 인해 할당된 시간이 소진되었거나 우선순위가 더 높은 프로세스가 도착했을 때 스케줄러에 의해 선점되는 상황에서 발생한다.

▍ 프로세스의 메모리 구조
하나의 프로세스가 실행될 때 운영체제는 해당 프로세스를 위한 독립적인 가상 주소 공간을 할당한다. 이 공간은 용도에 따라 논리적으로 몇 개의 영역으로 구분된다.
코드 영역은 실행 가능한 기계어 명령어가 저장되는 공간으로, 프로그램이 실행되는 동안 내용이 변경되지 않도록 읽기 전용으로 관리되는 경우가 일반적이다. 데이터 영역은 전역 변수와 정적 변수가 저장되는 공간으로, 초기값이 지정된 변수는 데이터 영역에, 초기화되지 않은 변수는 별도의 영역에 저장되어 프로그램 실행 시점에 0으로 채워지는 방식이 흔히 사용된다. 힙 영역은 프로그램 실행 중 동적으로 할당되고 해제되는 메모리 공간이며, 낮은 주소에서 높은 주소 방향으로 확장되는 구조를 갖는다. 스택 영역은 함수 호출 시 생성되는 지역 변수, 매개변수, 복귀 주소 등이 저장되는 공간으로, 힙과는 반대 방향으로 확장되며 함수 호출이 중첩될수록 그 크기가 늘어난다.
이러한 메모리 구조는 물리 메모리의 용량 제약을 극복하기 위해 가상 메모리 기법과 결합되어 운용된다. 가상 메모리는 프로세스가 실제 물리 메모리보다 큰 주소 공간을 사용할 수 있도록 지원하는 기법으로, 현재 사용하지 않는 메모리 페이지를 디스크의 스왑 영역으로 옮기고 필요한 시점에 다시 물리 메모리로 불러오는 방식으로 동작한다. 메모리를 관리하는 대표적인 방식으로는 페이징과 세그멘테이션이 있다.
페이징은 메모리를 동일한 크기의 블록 단위로 분할하여 관리하는 방식으로, 하드웨어적으로 처리하기에 유리하다는 장점이 있으며 외부 단편화가 발생하지 않는다는 특징이 있다. 다만 프로세스의 마지막 페이지가 페이지 크기의 배수와 일치하지 않을 경우 내부적으로 사용되지 않는 공간이 남는 내부 단편화가 발생할 수 있다. 세그멘테이션은 코드, 데이터, 스택처럼 의미 있는 논리적 단위로 메모리를 가변적인 크기로 분할하는 방식으로, 단편화의 양상이 페이징과는 다르게 나타나며 할당과 해제를 반복하는 과정에서 사용 가능한 공간들이 조각나는 외부 단편화가 발생할 수 있다.
메모리 접근 속도를 높이기 위해 CPU 내부의 메모리 관리 장치는 주소 변환에 사용되는 페이지 테이블 정보 가운데 최근에 사용된 항목을 별도의 고속 캐시에 저장해두는데, 이를 변환 색인 버퍼라고 부른다. 이 캐시는 프로세스가 전환될 때 대부분 무효화되어야 하므로, 잦은 프로세스 전환은 이러한 캐시 초기화로 인한 성능 저하를 동반할 수 있다.
운영체제가 사용하는 페이지 교체 정책도 시스템 성능에 영향을 준다. 대표적인 방식으로는 먼저 적재된 페이지를 먼저 내보내는 방식, 가장 오랫동안 사용되지 않은 페이지를 내보내는 방식, 사용 빈도가 가장 낮은 페이지를 내보내는 방식 등이 있으며 각각의 접근 방식에 따라 페이지 부재가 발생하는 빈도에 차이가 나타날 수 있다.

▍ 프로세스의 생성과 계층 구조
유닉스 계열 운영체제인 리눅스, macOS 등에서는 프로세스가 계층적인 구조로 생성되고 관리된다. 새로운 프로세스를 생성한 프로세스를 부모 프로세스라고 하며, 이로부터 생성된 프로세스를 자식 프로세스라고 부른다. 컴퓨터가 부팅되는 시점에는 시스템 전체의 최상위에 위치하는 최초의 프로세스가 생성되며, 이후의 모든 프로세스는 이 최초의 프로세스로부터 직간접적으로 파생되어 계층 구조를 형성한다.
이러한 계층적 프로세스 생성은 대체로 두 단계의 시스템 호출을 통해 이루어진다. 먼저 부모 프로세스는 자기 자신을 그대로 복제한 자식 프로세스를 생성하도록 운영체제에 요청한다. 이렇게 생성된 자식 프로세스는 부모와 거의 동일한 메모리 내용을 갖지만 별도의 프로세스 식별자를 부여받은 독립적인 개체이다. 이후 자식 프로세스는 자신이 적재된 메모리의 내용을 다른 프로그램의 내용으로 완전히 교체하는 요청을 수행함으로써 원하는 프로그램을 실행하게 된다. 반면 윈도우 운영체제는 이와 같은 복제 후 대체 방식이 아니라 새로운 프로세스를 생성하는 별도의 함수를 통해 직접 프로세스를 생성하는 방식을 사용한다는 차이가 있다.
▍ 프로세스 간 통신 방식
여러 프로세스는 원칙적으로 독립된 메모리 공간을 사용하기 때문에 서로의 데이터에 직접 접근할 수 없다. 그러나 협업이 필요한 작업을 수행하기 위해서는 프로세스 사이에 데이터를 주고받을 수단이 필요하며, 이를 프로세스 간 통신이라고 한다.
파이프는 한 프로세스가 기록한 데이터를 다른 프로세스가 순서대로 읽어갈 수 있는 통신 채널로, 선입선출 구조로 동작하며 기본적으로 단방향 통신을 지원한다. 이름이 없는 형태는 주로 부모와 자식 프로세스 사이의 통신에 사용되며, 이름이 있는 형태는 파일 시스템상에 존재하여 서로 관계가 없는 프로세스 사이의 통신도 가능하게 한다. 메시지 큐는 운영체제가 관리하는 대기열을 매개로 프로세스들이 메시지를 주고받는 방식으로, 비동기적인 통신을 지원하고 경우에 따라 메시지에 우선순위를 부여할 수 있다.
공유 메모리는 여러 프로세스가 동일한 메모리 영역에 직접 접근하여 데이터를 주고받는 방식으로, 운영체제의 개입이 상대적으로 적어 프로세스 간 통신 방식 가운데 가장 빠른 속도를 보이는 것으로 알려져 있다. 다만 여러 프로세스가 동시에 접근할 수 있는 만큼 데이터 일관성을 지키기 위한 별도의 동기화 장치가 함께 요구된다. 소켓은 네트워크를 매개로 하는 통신 방식으로, 같은 컴퓨터 내부의 프로세스뿐만 아니라 서로 다른 컴퓨터에 위치한 프로세스 사이의 통신도 지원하며 클라이언트와 서버 모델을 구현하는 데 널리 활용된다. 시그널은 특정 이벤트나 상태 변화를 비동기적으로 알리는 간단한 통신 수단으로, 프로세스가 다른 작업을 수행하는 도중에도 전달될 수 있다는 특징이 있다.

▍ 스레드의 개념과 프로세스 내에서의 위치
스레드는 프로세스 내부에서 실제로 실행되는 흐름의 단위를 의미한다. 하나의 프로세스는 하나 이상의 스레드를 가질 수 있으며, 하나의 프로세스 안에서 여러 스레드가 동시에 실행되는 방식을 멀티스레딩이라고 부른다. 프로세스 내부에 존재하는 코드 영역, 데이터 영역, 힙 영역은 그 프로세스에 속한 모든 스레드가 공유하지만, 스택 영역만큼은 각 스레드가 독립적으로 보유한다. 이는 각 스레드가 함수 호출과 지역 변수를 독립적으로 관리하면서도 필요한 데이터는 다른 스레드와 공유할 수 있도록 만들어주는 구조적 특징이다.
운영체제는 스레드의 실행 상태와 관련 정보를 저장하기 위해 스레드 제어 블록이라는 자료구조를 사용한다. 스레드 제어 블록에는 스레드 식별자, 프로그램 카운터, 레지스터 값, 스레드 고유의 스택 포인터 등이 저장되며, 해당 스레드가 속한 프로세스의 제어 블록과 연결되어 프로세스와 스레드 사이의 관계를 유지한다.
스레드가 종료되더라도 같은 프로세스에 속한 다른 스레드는 계속 실행될 수 있지만, 프로세스 자체가 종료되면 그에 속한 모든 스레드도 함께 종료된다는 점은 프로세스와 스레드의 종속 관계를 잘 보여준다.
▍ 프로세스와 스레드의 구조적 차이
프로세스와 스레드의 가장 근본적인 차이는 자원의 독립성 여부에 있다. 프로세스는 각각 독립된 메모리 공간과 시스템 자원을 할당받아 실행되기 때문에 한 프로세스에서 발생한 오류가 다른 프로세스에 직접적인 영향을 미치기 어려운 구조를 갖는다. 이는 안정성 측면에서 장점으로 작용하지만, 프로세스를 새로 생성하고 전환하는 데 상대적으로 많은 시간과 자원이 소요된다는 단점도 함께 갖는다.
반면 스레드는 같은 프로세스 내의 다른 스레드와 메모리 자원의 대부분을 공유하기 때문에 스레드 사이의 통신과 데이터 공유가 프로세스 사이의 통신보다 훨씬 빠르게 이루어질 수 있다. 또한 스레드 사이의 전환은 프로세스 사이의 전환보다 가벼운 편인데, 이는 같은 프로세스에 속한 스레드들이 동일한 페이지 테이블을 공유하기 때문에 주소 변환 캐시를 새로 구성할 필요가 없기 때문이다. 다만 메모리를 공유한다는 특성은 동시에 단점으로 작용하기도 하는데, 하나의 스레드에서 발생한 오류나 예외가 같은 프로세스에 속한 다른 스레드, 나아가 프로세스 전체의 비정상 종료로 이어질 위험이 존재한다.
아래의 표는 프로세스와 스레드의 주요 특성을 비교하여 정리한 것이다.

이와 같은 특성 차이로 인해 웹 브라우저처럼 안정성이 중요한 소프트웨어는 각 탭을 독립된 프로세스로 실행하는 방식을 채택하는 경우가 많고, 다수의 요청을 동시에 처리해야 하는 서버 애플리케이션은 멀티스레드 구조를 채택하여 통신 비용과 자원 사용량을 줄이는 방향을 택하는 경우가 많다. 다만 이는 절대적인 원칙이라기보다는 애플리케이션의 요구사항과 안정성, 성능 사이의 균형을 고려한 설계 선택에 가깝다.

▍ 운영체제 커널 관점에서의 스레드 구현
스레드는 사용자 수준에서 관리되는 사용자 스레드와 운영체제 커널이 직접 관리하는 커널 스레드로 구분할 수 있다. 사용자 스레드는 커널의 개입 없이 사용자 영역의 라이브러리를 통해 생성되고 관리되기 때문에 생성과 전환 속도가 빠르지만, 커널이 개별 스레드의 존재를 인식하지 못하기 때문에 하나의 스레드가 입출력 작업으로 대기 상태에 들어가면 같은 프로세스에 속한 다른 사용자 스레드까지 함께 대기하게 되는 한계가 있다. 커널 스레드는 운영체제 커널이 직접 스레드 단위로 스케줄링을 수행하기 때문에 이러한 문제를 피할 수 있지만, 생성과 전환 과정에서 커널의 개입이 필요하므로 상대적으로 더 많은 오버헤드가 발생한다.
실제 운영체제에서는 사용자 스레드와 커널 스레드를 연결하는 매핑 방식에 따라 여러 모델이 존재한다. 하나의 사용자 스레드가 하나의 커널 스레드에 일대일로 대응하는 방식은 구현이 비교적 단순하고 커널 수준의 병렬 처리가 가능하다는 장점이 있으며, 다수의 사용자 스레드를 하나의 커널 스레드에 대응시키는 방식은 사용자 수준에서의 전환 비용을 줄일 수 있지만 하나의 스레드가 블로킹되면 전체가 영향을 받는다는 단점이 있다. 이 두 방식을 절충하여 여러 사용자 스레드를 여러 커널 스레드에 유연하게 대응시키는 다대다 방식도 존재한다.
윈도우 운영체제의 경우 커널 내부에서 스레드를 관리하기 위해 몇 가지 자료구조를 계층적으로 사용한다. 커널 관점에서 스레드를 표현하는 자료구조에는 스레드의 상태, 동기화 객체, 해당 스레드가 속한 프로세스에 대한 정보, 우선순위 등이 포함되며, 이보다 더 낮은 수준에서 실제 스케줄링과 실행을 담당하는 자료구조가 별도로 존재하여 레지스터 상태와 커널 스택 정보 등을 관리한다. 사용자 모드에서 접근 가능한 스레드 관련 정보는 또 다른 자료구조에 저장되어 스레드 로컬 저장소나 예외 처리 정보, 사용자 스택의 범위 등을 담고 있다. 이처럼 커널 영역과 사용자 영역에 걸쳐 여러 자료구조가 유기적으로 연결되어 하나의 스레드를 구성한다는 점은 스레드 관리가 단순히 하나의 표에 정리될 수 있는 개념이 아니라 계층적인 시스템 설계의 산물임을 보여준다.

▍ 동기화 문제와 임계 구역
여러 스레드가 메모리를 공유하며 동시에 실행되는 환경에서는 공유 자원에 대한 접근이 겹치면서 예기치 않은 결과가 발생하는 경쟁 상태 문제가 발생할 수 있다. 이를 방지하기 위해 공유 자원에 접근하는 코드 영역을 임계 구역으로 지정하고, 한 번에 하나의 스레드만이 이 구역에 진입할 수 있도록 제어하는 동기화 기법이 사용된다.
대표적인 동기화 도구로는 상호 배제를 보장하는 락 계열의 기법과, 자원의 사용 가능한 개수를 계산하여 접근을 조절하는 세마포어 계열의 기법이 있다. 전자는 하나의 자원에 대해 오직 하나의 스레드만 접근을 허용하며 락을 획득한 주체만이 해제할 수 있는 소유권 개념을 가지는 경우가 많다. 후자는 소유권 개념 없이 허용된 자원의 개수를 변수로 관리하며, 자원을 점유하지 않은 다른 스레드도 신호를 보내는 연산을 수행할 수 있다는 점에서 순서 동기화나 자원 풀 관리와 같은 다양한 상황에 활용될 수 있다.
이러한 동기화 기법을 잘못 사용하면 여러 프로세스나 스레드가 서로 점유한 자원을 무한정 기다리게 되는 교착 상태가 발생할 수 있다. 교착 상태는 자원의 상호 배제, 이미 점유한 자원을 유지한 채 다른 자원을 추가로 기다리는 점유와 대기, 강제로 자원을 회수할 수 없는 비선점, 그리고 대기 관계가 순환 구조를 이루는 환형 대기라는 네 가지 조건이 동시에 충족될 때 발생한다는 점이 이론적으로 알려져 있다. 이를 예방하거나 회피하기 위한 다양한 알고리즘이 연구되어 왔으며, 자원 할당 이후의 상태가 안전한지를 미리 시뮬레이션하여 판단하는 방식 등이 대표적인 예로 언급된다.
▍ CPU 스케줄링과 프로세스 관리의 연결
준비 상태에 있는 여러 프로세스와 스레드 가운데 어떤 것에 CPU를 할당할지 결정하는 것이 스케줄링의 역할이다. 스케줄링 방식에 따라 시스템의 응답 속도, 처리율, 공평성 등이 달라지기 때문에 운영체제 설계에서 매우 중요한 부분을 차지한다.
프로세스의 특성에 따라 우선순위가 다른 여러 개의 정적인 대기열을 두고 각 프로세스를 해당 대기열에 배정하는 방식은 구현이 비교적 단순하지만, 대기열 사이의 이동이 불가능한 경우 우선순위가 낮은 대기열에 속한 프로세스가 계속해서 자원을 할당받지 못하는 현상이 발생할 수 있다. 이러한 문제를 완화하기 위해 프로세스의 실행 양상에 따라 대기열 사이의 이동을 허용하는 동적인 방식이 사용되기도 하는데, 할당된 실행 시간을 모두 소진한 프로세스는 하위 대기열로 이동시키고 오랫동안 대기한 프로세스는 상위 대기열로 승격시키는 방식을 통해 특정 프로세스가 지나치게 오래 기다리는 상황을 방지할 수 있다.
CPU가 실행하는 대상을 전환하는 과정을 문맥 교환이라고 하며, 이 과정에서 운영체제는 현재 실행 중이던 프로세스나 스레드의 레지스터 상태를 제어 블록에 저장하고 다음에 실행할 대상의 저장된 상태를 복원한다. 앞서 살펴본 것처럼 프로세스 사이의 문맥 교환은 서로 다른 페이지 테이블을 사용하기 때문에 주소 변환 캐시를 새로 구성해야 하는 부담이 있는 반면, 같은 프로세스에 속한 스레드 사이의 문맥 교환은 이러한 부담이 상대적으로 적다. 이 차이는 시스템 설계 시 프로세스 기반 병렬 처리와 스레드 기반 병렬 처리 가운데 무엇을 선택할지 판단하는 근거 가운데 하나로 작용한다.

▍ 마치며
프로세스와 스레드는 운영체제가 여러 작업을 동시에 처리하는 것처럼 보이게 만드는 핵심 메커니즘이며, 이를 뒷받침하는 것은 상태 전이 관리, 메모리 구조 설계, 프로세스 간 통신, 동기화 기법, 스케줄링 정책 등 여러 층위의 기술이 유기적으로 결합된 결과물이다. 프로세스는 독립성과 안정성에 강점을 갖는 반면 상대적으로 무거운 자원 소비를 동반하고, 스레드는 가볍고 빠른 전환과 통신을 제공하는 대신 오류 전파의 위험을 함께 안고 있다. 어느 한쪽이 절대적으로 우월하다고 단정하기보다는, 다루고자 하는 애플리케이션의 성격과 요구되는 안정성 수준에 따라 프로세스 기반 구조와 스레드 기반 구조를 적절히 선택하거나 병행하는 것이 합리적인 접근으로 볼 수 있다. 운영체제 내부의 이러한 원리를 이해하는 것은 소프트웨어를 설계하고 성능 문제를 진단하는 데 있어 여전히 유용한 기초 지식으로 남아 있다.

'연예이슈' 카테고리의 다른 글
| 리눅스 기본 명령어 20가지, 이것만 알면 서버 관리의 뼈대가 잡힌다 (0) | 2026.07.16 |
|---|---|
| Git과 GitHub의 차이, 그리고 첫 커밋까지: 5분 만에 이해하는 버전 관리의 핵심 원리 (0) | 2026.07.16 |
| CD 파이프라인이 소프트웨어 개발에 미치는 영향 (0) | 2026.07.15 |
| 인덱스가 SQL 조회 성능을 향상시키는 원리와 데이터베이스 설계 원칙 (0) | 2026.07.15 |
| 관계형 데이터베이스와 NoSQL 데이터베이스 비교: 구조, 성능, 확장성으로 살펴보는 선택 기준 (0) | 2026.07.15 |