개발자는 프로그램을 개발한다. 프로그램이란 어떤 작업을 위해 실행될 수 있는 파일이며 컴퓨터가 이해할 수 있는 명령어들의 모음이다.
프로세스는 이러한 프로그램이 실행되고 있는 상태이다.
OS의 관리를 받아 시스템 콜로 하드웨어 자원들을 사용할 수 있다.
동적인 상태를 위해 메모리에 올라간 형태이며 메모리는 용량이 낮아 우선 순위에서 밀린 프로세스는 Disk의 Swap 영역에 임시적으로 저장되기도 한다.
작업을 수행하고 있는 프로세스는 running 상태이며 CPU를 할당 받는다.
프로세스는 다음과 같은 구조를 가진다.
Heap 영역은 메모리의 낮은 곳부터 높은 곳으로 데이터가 쌓이고, 반대로 Stack 영역은 메모리의 높은 곳부터 낮은 곳으로 데이터가 쌓인다.
그 유명한 stack overflow가 발생하는 이유는 연쇄적인 함수 호출로 데이터가 반환되지 않아서 프로세스의 Stack 영역이 점점 커져 Heap 영역을 침범하는 것이다.
프로세스는 돌아가며 CPU를 할당받는다.
우리는 컴퓨터에서 여러가지 프로세스가 동시에 실행된다고 생각하지만, 컴퓨터는 매우 효율적으로 여러 프로세스들을 돌아가며 작업을 실행하기 때문에 동시에 실행된다고 착각하는 것이다.
그렇다면 프로세스가 CPU를 할당 받는 것이 무엇일까? - CPU가 프로세스의 작업을 수행하기 위해 CPU에 적재하는 것이며 CPU의 PC(Program Counter) 등 레지스터에 프로세스의 정보를 올리는 것이다.
다음 번의 프로세스가 CPU에 적재되기 위해서는 프로세스에 대한 정보가 필요할 것이며, 작업 중이던 프로세스 또한 CPU 할당을 해제할 때 다시 프로세스의 정보들을 어딘가에 저장해야 할 것이다.
따라서 프로세스의 정보들은 PCB(Process Control Block)에 저장된다.
프로세스는 식별을 위해 Process ID를 가진다.
프로세스에는 Ready, Running, Waiting 등의 상태를 가지기 때문에 Process State에 이를 저장한다.
Program Counter에는 다음 번에 실행할 명령어의 주소를 저장하며, Pointer에는 부모, 자식 프로세스의 주소, 할당된 자원들에 대한 주소, 현재 프로세스의 위치 등이 기억된다.
또한 PCB에는 스케줄링을 위해 우선순위, 최종 실행 시간, CPU 점유 시간 등이 저장될 수 있다.
스레드란 프로세스 내에서 실행되는 여러 흐름의 단위이다.
하나의 프로세스에서 병렬적으로 여러 개의 작업을 수행하기 위하여 각 작업을 스레드화 하여 멀티 스레드로 처리할 수 있다.
하나의 스레드는 독자적인 Stack 영역만을 가지며 나머지 Code, Data, Heap 영역은 공유한다.
독립적인 Stack 영역을 가지기 때문에 하나의 프로세스에서 여러 개의 실행 흐름을 가질 수 있지만, Data와 Heap 영역을 공유하기 때문에 원치 않은 결과가 나올 수 있으므로 동시성에 대하여 신경써야 한다.
하나의 응용 프로그램을 여러 개의 프로세스로 나누는 것을 멀티 프로세스라고 한다.
만약 하나의 프로세스로 실행한다면 오류가 발생하면 전체의 시스템에 문제가 생기지만, 멀티 프로세스는 해당 프로세스에서만 문제가 발생한다.
하지만 앞서 살펴본 것처럼 각 프로세스는 독립적인 메모리 영역을 할당받기 때문에 프로세스 간 IPC를 사용하여 통신할 수 있지만 데이터를 공유하기 힘들다.
또한 프로세스가 늘어나는 것이므로 CPU를 할당받기 위한 컨텍스트 스위칭에서 오버헤드가 발생하게 된다.
멀티 스레드는 하나의 프로세스에서 병렬적으로 일을 처리하기 위해 여러 작업을 스레드화 해서 여러 개의 작업을 수행하는 것이다.
스레드는 Stack 영역을 제외한 메모리 영역을 공유하기 때문에 자원에 있어서 효율적이다.
또한 스레드 하나의 작업 단위는 프로세스에 비해 작기 때문에 멀티프로세스보다 컨텍스트 스위칭의 오버헤드가 저렴하다.
하지만 하나의 스레드에서 문제가 발생하면 전체 프로세스가 영향을 받고, Stack 영역 외 메모리 영역을 공유하기 때문에 동기화 문제가 발생할 수 있다.