프로그램이란 원하는 어떠한 일을 하기 위해 계획된 방법과 절차에 의해 작성된 일련의 순서나 목록을 말합니다.
즉, 컴퓨터 프로그램은 컴퓨터에서 실행될 때 특정 작업을 수행하는 일련의 명령어들의 모음입니다.
보조기억 장치에 저장되어 있던 프로그램이 메모리에 올라와 실행되면 프로세스가 됩니다.
프로세스란 실행 중인 프로그램을 말합니다.
보조기억장치에 저장된 프로그램을 메모리에 적재하고 실행하는 순간 그 프로그램은 프로세스가 됩니다.
프로세스 제어 블록은 프로세스와 관련된 정보를 저장하는 자료 구조입니다.
운영체제는 빠르게 번갈아 수행되는 프로세스의 실행 순서를 관리하고, 프로세스에 CPU를 비롯한 자원을 배분하기 위해 프로세스 제어 블록을 이용합니다.
PCB는 커널 영역에서 생성되며, 프로세스 생성 시에 만들어지고 실행이 끝나면 폐기됩니다.
실행 중이던 프로세스에서 다른 프로세스로 실행 순서가 넘어갈 때, 실행되던 프로세스는 지금까지의 중간 정보를 백업해야 합니다. 그래야 다음 차례가 왔을 때 이전까지 실행했던 내용에 이어 실행을 재개할 수 있습니다.
이렇게 하나의 프로세스 수행을 재개하기 위해 기억해야 할 정보를 문맥(context) 이라고 합니다.
한 프로세스의 문맥은 해당 프로세스의 PCB에 표현되어 있습니다.
프로세스 간 실행을 전환하는 것을 문맥 교환이라고 합니다.
프로세스가 CPU를 사용할 수 있는 시간이 다 되거나 예기치 못한 상황이 발생하여 인터럽트가 발생하면,
운영체제는 기존 프로세스의 문맥을 PCB에 백업하고,
새로운 프로세스를 실행하기 위해 문맥을 PCB로 부터 복구하여
새로운 프로세스를 실행합니다.
문맥 교환이 자주 발생하면 여러 프로세스가 끊임없이 빠르게 번갈아 가며 실행되어 사용자 입장에서는 프로세스들이 동시에 실행되는 것처럼 보입니다. 하지만 문맥 교환을 너무 자주하면 오버헤드가 발생할 수 있습니다.
프로세스의 메모리 영역은 크게 코드 영역, 데이터 영역, 힙 영역, 스택 영역으로 나뉘어 있습니다.
실행할 수 있는 코드(기계어로 이루어진 명령어)가 저장됩니다. 여기에는 데이터가 아닌 CPU가 실행할 명령어가 담겨 있기 때문에 쓰기가 금지되어 있습니다.
데이터 영역은 전역 변수 등 프로그램을 실행하는 동안 유지할 데이터가 저장되는 공간입니다.
프로그래머가 직접 할당할 수 있는 저장 공간입니다.
데이터를 일시적으로 저장하는 공간입니다. (매개 변수, 지역 변수 등)
코드 영역과 데이터 영역은 크기가 고정된 정적 할당 영역이고, 힙 영역과 스택 영역은 실시간으로 크기가 변할 수 있는 동적 할당 영역입니다.
프로세스를 생성 중인 상태입니다. 이제 막 메모리에 적재되어 PCB를 할당받은 상태입니다.
생성 상태를 거쳐 준비 상태가 됩니다.
준비 상태는 당장이라도 CPU를 할당받아 실행할 수 있지만, 자신의 차례가 아니라 기다리고 있는 상태입니다.
준비 상태인 프로세스가 실행 상태로 전환되는 것을 디스패치(dispatch)라고 합니다.
CPU를 할당받아 실행 중인 상태입니다.
할당된 일정 시간 동안만 CPU를 사용할 수 있으며, 할당된 시간이 지나면(타이머 인터럽트가 발생하면) 다시 준비 상태가 됩니다.
실행 도중 입출력장치를 사용하여 입출력장치의 작업이 끝나기를 기다려야 한다면 대기 상태가 됩니다.
프로세스가 실행 중에 입출력 작업을 요청한 경우, 입출력 작업은 CPU에 비해 처리 속도가 느리기 때문에, 프로세스는 입출력장치가 작업을 끝낼 때까지(입출력 완료 인터럽트를 받을 때까지) 기다려야 합니다.
이렇게 입출력장치의 작업을 기다리는 상태를 대기 상태라고 합니다.
입출력 작업이 완료되면 해당 프로세스는 다시 준비 상태로 CPU 할당을 기다립니다.
프로세스가 종료된 상태입니다. 프로세스가 종료되면 운영체제는 PCB와 프로세스가 사용한 메모리를 정리합니다.
fork()는 자기 자신 프로세스의 복사본을 자식 프로세스로 생성하는 시스템 콜입니다.
부모 프로세스는 fork 시스템 콜을 통해 자신의 복사본을 자식 프로세스로 생성합니다. PID나 메모리 위치는 다르지만, 자식 프로세스는 부모 프로세스의 복사본이기 때문에 부모 프로세스의 자원들이 상속됩니다.
exec()는 자신의 메모리 공간을 새로운 프로그램으로 덮어쓰는 시스템 콜입니다.
자식 프로세스는 exec 시스템 콜을 통해 새로운 프로그램으로 전환됩니다. exec를 호출하면 코드 영역과 데이터 영역의 내용이 실행할 프로그램의 내용으로 바뀌고, 나머지 영역은 초기화됩니다.
예를 들어, bash 셸에서 ls 명령어를 입력하면,
스레드란 프로세스 안에서 실행되는 여러 흐름의 단위입니다.
하나의 프로세스는 여러 스레드를 가질 수 있으며, 스레드를 이용하면 하나의 프로세스에서 여러 부분을 동시에 실행할 수 있습니다.
프로세스 안에서 스레드들은 각각 레지스터와 스택만 따로 할당받고, 코드/데이터/힙 영역은 서로 공유하며 사용합니다.
즉, 스레드들은 실행에 필요한 최소한의 정보(레지스터, 스택)만을 유지한 채 프로세스 자원을 공유하면 실행됩니다.
여러 프로세스를 동시에 실행하는 것 멀티 프로세스(multiprocess),
여러 스레드로 프로세스를 동시에 실행하는 것 멀티 스레드(multithread) 라고 합니다.
프로세스끼리는 기본적으로 자원을 공유하지 않지만, 스레드끼리는 같은 프로세스 내의 자원을 공유한다는 차이가 있습니다.
그래서 멀티 프로세스 환경에서는 하나의 프로세스에 문제가 생겨도 다른 프로세스에 지장이 적거나 없다는 장점이 있습니다. 하지만 각각 독립된 메모리 영역을 가지고 있어, 작업량이 많을 수록 오버헤드가 발생할 수 있습니다.
(오버헤드(overhead)는 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 · 메모리 등을 말한다.)
반면에 스레드들은 프로세스의 자원을 공유하기 때문에 여러 프로세스를 병렬 실행하는 것보다 메모리를 더 효율적으로 사용할 수 있으며 서로 협력과 통신에 유리합니다. 하지만, 하나의 스레드에 문제가 생기면 자원을 공유하기 때문에 프로세스 전체에 문제가 생길 수 있습니다.
프로세스는 매우 독립적으로 기본적으로 자원을 공유하지 않지만, 경우에 따라서 프로세스가 협력을 해야만 효율적으로 실행되는 경우도 있습니다.
그래서 프로세스끼리도 자원을 공유하고 데이터를 주고받는 협력 메커니즘이 존재합니다.
이렇게 프로세스 간 자원을 공유하고 데이터를 주고받는 것을 프로세스 간 통신(IPC) 라고 합니다.
IPC에는 크게 두 가지 방법이 있습니다.
프로세스가 서로 메시지를 주고받으며 실행되는 방식입니다. 하지만 프로세스는 독립적이기 때문에 자기 메모리 주소 공간만 볼 수 있으며, 다른 프로세스에게 직접 메시지를 전달하는 방법은 원칙적으로는 존재하지 않습니다. 그래서 커널을 통해(시스템 콜을 통해) 메시지를 전달합니다.
프로세스들이 서로 공유하는 메모리 영역을 두어 데이터를 주고 받을 수 있습니다. 프로세스들이 공유할 수 있는 메모리 영역을 공유 메모리(shared memory) 라고 합니다.
프로세스 생성 시 기본적으로 메모리 공간을 공유하지 않기 때문에 이를 위한 시스템 콜을 해야 합니다.
Reference
혼자 공부하는 컴퓨터 구조+운영체제
https://higunnew.tistory.com/26
https://gyoogle.dev/blog/computer-science/operating-system/Process%20vs%20Thread.html