컴퓨터에서 연속적으로 실행되는 컴퓨터 프로그램을 말한다. 프로그램은 저장장치에 저장된 코드를 말하며 프로세스는 이를 구동하여 프로그램과 상태가 메모리 상에서 실행되는 작업 단위를 말한다. 프로그램이 실행되기 위해서운영체제로 부터 독립된 메모리 영역을 할당 받아야 한다.(Code, Data, Stack, Heap)
우리는 보통 동시에 여러 프로그램(프로세스)를 실행한다. 겉으로 보이기에는 동시에 실행되고 관리되는것처럼 보이지만 동시는 아니다. CPU는 한번에 한개의 명령어만 실행할 수 있다. CPU는 재빠르게 여러 프로세스들을 번갈아가며 실행하고 관리하고 있는 것이다. CPU는 매우 빠르기 때문에 우리는 동시에 처리되고 있다고 느낄 뿐이다. CPU가 여러 프로세스들을 번갈아가며 처리하는 것을 Context Switching(문맥교환)이라고 한다.
하나의 프로세스가 이미 CPU를 사용중인 상태에서 다른 프로세스가 CPU를 사용하기 위해 이전 프로세스의 상태를 저장하고 새로운 프로세스의 상태를 적재하는 것을 말한다. 여러 프로세스의 효과적인 문맥교환을 통해 멀티태스킹을 할 수 있다. 이와 같은 문맥교환은 Scheduler에 의해 발생한다. 스케쥴러는 효율적인 CPU사용을 도와준다.
위의 프로세스 문맥 교환을 나타내는 그림을 보자. 프로세스 P0는 실행, P1는 대기 상태이다. 인터럽트나 시스템 콜에 의해 운영체제는 P0의 상태를 대기 상태로 전환하면서 프로세스에 대한 정보를 PCB0에 저장한다. 이후 P1이 실행될 순서가 되면 운영체제는 PCB1에서 P1에 대한 정보를 복원하며 P1의 상태를 실행 상태로 전환한다. 이후 문맥 교환에 의해 P1의 상태는 다시 PCB1에 저장되고 P1은 대기 상태로 전환된다.
PCB(Process Control Block)은 운영체제가 프로세스를 표현한 자료구조이다. 특정 프로세스에 대한 정보를 갖고 있다. 각 프로세스가 생성될 때마다 고유의 PCB가 생성되고 프로세스가 완료되면 PCB는 제거된다. 프로세스간 문맥교환이 일어나면서 프로세스는 진행하던 작업들을 PCB에 저장하고 이후에 자신의 순서가 왔을 때 이를 이어서 처리한다. PCB에는 다음과 같은 프로세스의 정보가 저장된다.
프로세스는 생성되어 종료되기 전까지 항상 메모리에 상주하며 다양한 상태를 갖는다. 프로세스가 활성화되어 종료되기까지의 살아있는 시간을 프로세스의 생명주기라고 한다.
프로세스의 생명주기는 다음과 같은 다섯단계로 나뉜다.
스케쥴러는 대기 큐에 있는 프로세스들을 특정한 우선순위를 기반으로 CPU를 할당받게 해준다. 다음 세가지 목적에 의해 스케쥴링을 수행한다.
위의 세가지 목적을 수행하기 위해 스케쥴러는 다음의 스케쥴링 알고리즘 중 하나를 갖는다.
이미 할당된 CPU를 다른 프로세스가 강제로 빼앗아 사용할 수 없는 스케쥴링 기법이다. 선점 방식보다 호출의 빈도가 낮고 문맥 교환에 의한 오버헤드도 적다. 따라서 일괄처리 시스템에 적합하다. 하지만 CPU사용시간이 긴 하나의 프로세스에 의해 다른 프로세스들을 오랜시간동안 대기시킬 수 있다.
하나의 프로세스가 CPU를 할당받고 실행하고 있는 와중에 우선순위가 높은 다른 프로세스가 CPU를 강제로 빼앗아 사용할 수 있는 기법이다. 비선점 방식보다 호출의 빈도가 높으며 문맥 교환에 의한 오버헤드가 크다. 빠른 응답시간을 요구하는 대화식 시분할 시스템에 적합하다.
RR: Round Robin → 프로세스마다 정해진 시간만큼 수행하고 작업이 끝난 프로세스는 대기 큐의 마지막에 가서 재할당을 기다린다.
Multilevel Queue → 대기 큐를 여러개로 나누어 큐마다 다른 스케쥴링 알고리즘을 갖는다.
프로세스를 특정한 그룹들로 분리할 수 있는 경우 그룹에 따라 다른 큐와 알고리즘을 둔다.
프로세스가 특정 그룹의 준비상태 큐에 들어갈 경우 다른 준비상태 큐로 이동할 수 없다.
하위 준비상태 큐의 프로세스가 실행되는 중이더라도 상위 준비상태 큐에 프로세스가 새로 들어오면 CPU는 상위 프로세서에게 할당되어야 한다.
각 프로세스들은 별도의 공간에서 실행되기 때문에 한 프로세스에서 다른 프로세스의 메모리영역에 접근할 수 없다. 만약 프로세스가 다른 프로세스에 접근하려면 IPC를 사용해야 한다. IPC에는 크게 두가지 모델이 있는데 하나는 Message Passing모델이고 다른 하나는 Shared Memory모델이다.
전자의 방식이 Messagin Passing모델이고 후자의 방식이 Shared Memory모델이다.
Message Passing모델의 경우 메시지를 전달하기 위해 커널을 들린다. 이 과정에서 User Level과 Kernel Level을 넘나들게 되고 매번 system call이 호출되고 이에 따른 오버에드도 발생된다.
Shared Memory모델의 경우 프로세스 사이에 공유 공간이 존재하기 때문에 시스템 호출이 필요하지 않다. 이로 인해 커널 의존성도 낮고 속도도 빠르다. 하지만 공유 공간에 대한 제한이 존재한다.
프로세스 내에서 실행되는 흐름의 단위이다. 스레드는 운영체제의 스케쥴러에 의해 독립적으로 관리될 수 있는 프로그래밍 된 명령어의 가장 작은 시퀀스이다. 보통 하나의 프로그램은 하나 이상의 프로세스를 갖고 있으며 하나의 프로세스는 반드시 하나 이상의 스레드를 갖고 있다. 프로세스를 생성하면 기본적으로 하나의 메인스레드가 생성된다.
위 그림과 같이 프로세스는 실행될 때 운영체제로부터 각각 독립된 메모리 영역을 할당받는다. 스레드는 프로세스 내에서 스택 영역만 별도로 할당받고 부모 프로세스의 Code, Data, Heap영역은 공유한다. 따라서 프로세스 내의 자식 스레드들은 서로 주소공간이나 자원을 공유하면서 실행될 수 있다.
멀티프로세스에서 각 프로세스는 독립적으로 실행되며 각각 별도의 메모리 공간을 갖고 있다. 멀티프로세스는 하나의 프로그램을 여러개의 프로세스로 구성하여 각 프로세스가 하나의 작업을 처리하도록 하는 것이다.
하나의 어플리케이션을 여러개의 스레드로 구성하여 하나의 스레드가 하나의 작업을 처리하도록 하는 것이다. 만약 단일 스레드로 네트워크나 데이터베이스 통신과 같은 긴 작업을 수행하는 경우 다른 작업을 처리할 수 없기 때문에 여러개의 스레드를 사용한다.
스레드들은 부모 프로세스의 메모리 공간을 공유하는데 여러 스레드가 동일한 메모리 공간을 접근하면서 동기화 문제가 발생한다.
스레드들 간에 한 번에 하나의 스레드만 공유자원에 접근하게 함으로써 동기화(임계영역) 문제를 해결할 수 있다.
멀티스레드는 프로세스 내 자원을 공유하기 때문에 멀티프로세스에 비해 시스템 자원 소모가 줄어든다.
프로세스간 IPC를 사용하는 것은 비용이 크다. 스레드의 경우 공유자원의 이용을 통해 스레드간 통신의 비용이 적다. 또한 프로세스 간 문맥교환은 스레드 간 문맥교환보다 느리다. 그 이유로 스레드는 문맥 교환 과정에서 Stack영역만 처리하면 되기 때문이다.
멀티스레드가 동일한 공간을 공유하면서 생기는 임계영역 문제가 있다. 멀티프로세스의 경우 프로그램의 문제가 생기면 프로그램을 중단시키고 다시 시작하면 되지만 멀티스레드 방식의 경우에는 하나의 스레드가 공유공간을 망가뜨리면 해당 공간을 공유하는 모든 스레드를 망가뜨릴 수 있다.
운영체제 프로세스 생애주기(Process Lifecycle)에 대해서
[OS] - 임계 영역(Critical Section)과 해결방안(Lock / Semaphore / Monitor)