프로세스
프로세스란 실행파일로 존재하는 프로그램을 메모리에 적재하여 CPU를 할당받아 실행되는 것을 의미한다.
즉, 프로그램이 프로세스가 아니라, 프로그램이 메모리에 적재되었을 때가 프로세스이다. 작업관리자에서 보는 PID가 바로 프로세스 종류들이다.
메모리 적재 이유
메모리에 적재한다는 것은 디스크(하드디스크, SSD)에서 메모리(RAM)으로 옮겨 적재하는 것이다. 적재하는 이유는 CPU가 직접 접근할 수 있는 기억장치는 메모리이기 때문에 적재를 통해 CPU가 PC register를 통해 연산을 할 수 있기 때문이다.
메모리 공간
- 프로세스에 할당되는 메모리 공간은 Code, Data, Stack, Heap 4개의 영역으로 이루어져 있다.
- Stack : Compile 시점에 메모리 영역의 크기가 결정된다.
- Heap : runtime 시점에 메모리 영역의 크기가 결정된다.
CPU 연산 과정
- 프로그램을 실행한다는 것은 CPU가 연산을 하는 것이다. 이 때 연산할 코드의 위치를 PC(Program Counter) register에 저장되어 있다. 즉, 프로세스 Code 영역의 명령어 중 다음번에 연살할 명령어의 주솟값을 PC register에서 순차적으로 가리키게 되고, 해당 명령어를 읽어와서 CPU가 연산하게 되면 프로세스가 실행하게 된다.
프로세스 상태
- CPU 코어가 하나의 프로세스만 실행하는 경우가 아니라면 프로세스는 계속해서 상태가 변한다.
- new : 생성 , running : 실행 중, waiting : 대기, ready : 할당되기를 기다림, terminated : 종료
- 이 프로세스 상태의 정보는 PCB 내부에서 저장되어 관리된다.
멀티 프로세스
멀티 프로세스란 2개 이상의 프로세스가 동시에 실행되는 것을 의미한다. 이때 동시란 단어에는 동시성(Concurrency)과 병렬성(Parallelism) 두 가지가 존재한다.
멀티 프로세스 환경에서프로세스 간 파이프, 소켓, 공유 메모리 등을 사용해서 프로세스 간 통신을 한다.
동시성 : CPU 코어가 1개가 여러 프로세스를 계속 번갈아가면서 연산하는 시분할 시스템(Time sharing System)을 의미한다.
병렬성 : CPU 코어가 여러 개 일때, 각각의 코어가 프로세스를 연산하면서 프로세스가 동시에 실행되는 것을 의미한다.
메모리 관리
여러 프로세스가 메모리에 적재된 경우, 각 프로세스 별로 영역을 침범하지 않도록 운영체제가 관리해준다. 따라서 각 프로세스는 자신의 메모리 영역에만 접근할 수 있다.
CPU 연산 과정 - Context
동시성인 시분할 시스템에서 CPU는 짧은 시간 동안 각 프로세스들의 일정부분의 명령을 수행한다. 이 때 각 프로세스 별로 다음에 실행할 주솟값이 필요하게 되는데, 이 정보를 Context라고 한다. 이 Context 정보들은 PCB(Process Control Block)에 저장되어 있다.
PCB
PCB는 운영체제가 프로세스를 표현한 자료구조로 보호된 메모리 영역 안에 저장된다. PCB안에는 프로세스 번호, 상태, PC 레지스터, CPU 스케쥴링 정보, 메모리 주솟값 등의 정보를 담고 있다.
Context Switch
실행중인 프로세스에서 다른 프로세스로 CPU의 제어권을 넘겨주는 것을 Context Switch라고 한다. 이 때 이전의 프로세스의 상태를 PCB에 저장하여 보관하고, 새로운 프로세스의 PCB를 읽어서 보관된 상태를 복구하는 작업이 이루어진다.
IPC (Inter-Process Communication)
프로세스는 각자 자신만의 독립적인 주소 공간을 갖기 때문에 다른 프로세스가 참조하는 것을 허용하지 않는다.
이 때 IPC 기법을 통해 프로세스 간 통신을 가능하게 해준다. IPC에는 기본적으로 공유 메모리, 메시지 전달 모델이 존재한다.
공유 메모리 (shared memory)
프로세스들 간 주소 공간의 일부를 고유하는 방식이다. 프로세스가 공유 메모리 할당을 커널에게 요청하면, 커널은 프로세스에 메모리 공간을 할당해준다. 공유 메모리 영역이 구축된 이후에는 모든 접근이 일반적인 메모리 접근으로 취급되기 때문에 더 이상의 커널 도움 없이 각 메모리 영역에 접근할 수 있다. 대표적인 예시로는 공유메모리와 POSIX가 있다.
커널의 관여 없이 데이터를 통신할 수 있기 때문에 IPC 속도가 빠르다는 장점이 있다.
동시에 같은 메모리 위치에 접근하게 되면 동기화 문제가 발생할 수 있다.
메시지 전달 (Message passing)
System Call을 사용하여 커널을 통해 send msg 와 receive msg라는 연산을 제공 받는다. (A 프로세스가 B 프로세스에게 메시지 전달을 위해 중간에 커널을 이용)
메모리 공유보다는 속도가 느리지만, 충돌을 회피할 필요가 없기 때문에 적은 양의 데이터를 교환하는 데 유용하다.
대표적인 예시로는 pipe, socket, message, queue 등이 있다.
쓰레드
Thread는 한 프로세스 내부에서 실행되는 작업의 단위이다. 각 쓰레드는 속해있는 프로세스의 Stack 메모리를 제외한 Heap, Data, Code 영역을 공유할 수 있다. 이 때 Stack 영역을 공유하지 않는 것은 독립적 함수를 호출함으로 개별적인 기능을 수행하기 때문이다. (프로세스로부터 독립적인 스택 영역을 할당 받는 것)
MultiThread는 하나의 프로세스 내부에서 여러 쓰레드를 두어 작업을 병렬 처리하는 것을 의미한다. 쓰레드들은 작업 영역들을 공유(Stack 제외)하게 된다. 쓰레드도 프로세스처럼 쓰레드 간에 Context Switch가 발생한다. 따라서 쓰레드 별 PC register를 갖고 있는다.
멀티 프로세스 vs 멀티 쓰레드
- 두 방법은 동시에 여러 작업을 수행한다는 측면에서 유사한 면이 있지만, 각 기능 별로 장단점이 존재한다.
- 메모리 구분이 필요할 때는 멀티 프로세스가 유리하고, 데이터 공유가 잦은 경우에는 멀티 쓰레드를 사용하는 것이 유리하다.
- ContextSwitching 과정에서 멀티 프로세스가 느린 이유는 PC register를 변경하기 위한 작업이 많기 때문이다.
- 안정성의 경우 멀티 쓰레드에선 동기화 문제가 발생할 수 있기 때문에 낮다고 볼 수 있다.
멀티 프로세스로 할 수 있는 작업을 멀티 쓰레드를 주로 사용하는 이유
- 운영체제가 시스템 자원을 효율적으로 관리하기 위해 스레드를 사용한다.
- 멀티 프로세스로 실행되는 작업을 멀티 스레드로 실행할 경우, 프로세스를 생성하여 자원을 할당하는 System Call이 줄어들어 자원을 효율적으로 관리할 수 있다.
- 프로세스 간의 통신 보다, 스레드 간의 통신 비용이 적으므로 통신 부담이 줄어든다. (프로세스는 독립 구조이기 때문)
- 단, 멀티 스레드는 전역 변수를 자원 공유하므로 동기화 문제, 교착 상태가 발생할 수 있다.
멀티 쓰레드 / 프로세스 동기화 문제
멀티쓰레드는 전역 변수를 공유하기 때문에 동시에 같은 전역변수에 접근한다면 결과 값이 덮어씌워질 수 있다. 멀티 프로세스에서는 IPC 중 공유메모리 방식을 사용하면 마찬가지로 동기화 문제가 발생한다. 이러한 동기화 문제가 발생할 수 있는 변수를 임계구역 문제라하고, 이 문제를 해결하기 위해 뮤텍스(Mutual Exclusion) 와 세마포어(Semaphore) 방식이 있다.
뮤텍스 : 동시에 접근을 막는 방식으로 접근한 쓰레드가 있으면 Lock 신호를 줘서 막음으로 다른 쓰레드 들이 접근할 수 없도록 한다. 즉, 인터럽트를 콩해 공유데이터의 손상을 막는다. (단일 처리만 가능 - 이진 세마포어라고도 불림)
세마포어 : 뮤텍스가 접근만 동기화한다면, 세마포어는 접근 순서까지 동기화를 시킨다. (지정한 변수만큼 다중 처리 가능)
뮤텍스는 오직 1개의 프로세스 혹은 스레드만이 공유 자원에 접근할 수 있고, 세마포어는 지정된 변수의 값만큼 접근할 수 있다.
세마포어는 운영체제 혹은 커널 단위에서 해당 리소스 변수가 관리되어 현재 공유 자원을 사용중인 대상 뿐아니라 다른 프로세스 및 스레드도 잠금 상태를 해제할 수 있지만, 뮤텍스는 락을 가진 프로세스 혹은 스레드만 해제할 수 있다.
임계구역 문제 해결
임계구역 (공유된 자원)에서 발생하는 문제들은 3가지 조건을 충족하면 해결할 수 있다.
- Mutex(상호 배제) : 하나의 프로세스가 임계구역에 들어가 있으면, 다른 프로세스는 들어갈 수 없다.
- Progress(진행) : 임계구역에 들어간 프로세스가 없다면, 어느 프로세스가 들어갈 것인지 적절히 선택
- Bounded Waiting(한정 대기) : 기아 상태를 방지하기 위해, 한 번 들어갔다 나온 프로세스는 제한을 준다.
참고로 임계 구역에 진입하기 위해선 entry
section에서 진입 허가를 받아야 접근할 수 있고 실행이 끝나면 exit
section으로 퇴출하게 된다. 즉, 이 방식을 사용하여 임계영역의 원자성을 보장하여 동기화를 처리한다.
교착 상태 (Deadlock)
교착 상태란 둘 이상의 쓰레드가 실행 중인 작업을 서로 기다리고 있을 때, 발생하는 무한 대기 현상을 의미한다.
교착상태 발생 조건
교착상태가 발생하는 조건에는 다음 4가지 조건이 동시에 성립할 때 교착상태가 발생할 수 있다. (무조건 발생은 아니다.)
상호 배제 (mutual exclusion)
- 동시에 한 쓰레드만 자원을 점유할 수 있는 상황
- 다른 쓰레드가 자원을 사용하려면 자원이 방출될 때까지 기다려야하는 상황
점유 대기 (hold-and-wait)
- 쓰레드가 자원을 보유한 상태에서 다른 쓰레드가 보유한 자원을 추가로 기다리는 상황
비선점(no preemption)
- 다른 쓰레드가 사용 중인 자원을 강제로 선점할 수 없는 상황
순환 대기 (circular wait)
- 대기 중인 쓰레드들이 순환 형태로 자원을 대기하고 있는 상황
교착상태 해결
교착 상태를 해결하는 방법으론 무시, 예방, 회피, 탐지-회복 4가지가 존재한다.
무시
- 데드락이 발생확률이 낮을 시스템 환경에서 무시하는 방법
- 시스템 성능 저하가 없는 큰 장점이 있어, 현재 시스템은 데드락이 거의 발생하지 않기 때문에 주로 사용
예방
- 교착 상태의 4가지 조건 중 하나가 성립하지 않도록 만드는 방법 (자원 사용의 효율성이 떨어지고 비용이 크다.)
회피
- 쓰레드의 요청 정보를 확인하여 순환 대기가 발생하지 않도록 자원을 할당하여 회피하는 방법
- 은행원 알고리즘 기법
- 안전 상태 : 각 프로세스가 요구한 최대 요구량만큼 자원을 할당해줄 수 있는 상태 - 안전순서열 존재
- 불안전 상태 : 안전순서열이 존재하지 않는 상태로 교착 상태가 발생할 여지가 발생
탐지-회복
- 시스템 검사를 통해 데드락을 탐지하고 회복 시키는 기법 (자원 사용의 효율성이 떨어지고 비용이 크다.)
References
https://blog.yevgnenll.me/os/process-concepts-process-state-and-managed-in-memory