[문과 코린이의 IT 기록장] 운영체제(OS) - 프로세스(Process) (프로세스의 개념, 프로세스의 상태 (Process State), PCB, 문맥 교환 (Context Switch), 프로세스를 스케줄링 하기 위한 큐, 스케줄러, Thread)
1. 프로세스의 개념
1) 프로세스 : 실행중인 프로그램
2) 프로세스의 개념을 이해할 때 중요한 점 : 프로세스의 문맥 (context)
* 어떤 단어가 있으면, 그 단어가 어떠한 의미로 사용되는지 문맥을 통해 파악해야 함.
- 프로세스 문맥이란, 프로세스의 특정 시점을 놓고 봤을 때, 그 시점이 어떤 상태(PC register가 어느 코드를 가리키는지, 그 지점에서 Code/Data/Stack은 어떤 상태인지 등 )에 있는지를 정확하게 파악하는 것을 의미함.
- 즉 프로세스 문맥은 아래와 같은 것을 포함한다.
a. CPU 수행 상태를 나타내는, 하드웨어 문맥 (PC, 각종 register)
ex. PC가 어디를 가리키고 있는가, register에 어떤 값을 넣고 있었는가 등
b. 프로세스 메모리에 담긴 내용을 나타내는, 프로세스의 주소 공간 (Code, Data, Stack)
ex. 어떤 코드를 담고 있고, 변수의 값은 어떻게 변경되었고, Stack에 어떤 내용이 쌓여있으며 실행되었는가 등
c. 프로세스 관련 커널 자료 구조 (PCB(Process Control Block), Kernel stack)
ex 1. 운영체제가 PCB들에 대해서 어떤 값을 가지고 어떻게 평가하고 있는가 등
* 운영체제의 역할 중 하나 : 컴퓨터 내부에서 돌아가고 있는 프로세스들을 관리하는 역할을 함. 즉, 운영체제는 그 프로세스들을 관리하기 위해서 자신의 Data 영역에 프로세스당 자료구조(PCB)를 두고 관리하고 있음. 주로, CPU/Memory 할당 정도에 대해 고민하거나, 잘못된 행위를 하지는 않은지 판단하는 역할을 함.
ex 2. System call과 같은 상황에서, 커널은 어떤 프로세스의 부탁을 받고 어떤 행동을 실행해야 할지 모두 다름. 그 프로세스의 현재 상태를 규명하기 위해서 Kernel stack이 어떻게 쌓여있는지 파악해야 함
- 이러한 정보들을 지니고 있으면, 프로세스가 현재 어떠한 상태에 있는지 정확하게 규명할 수 있다.
- 프로세스가 하나만 실행되면 프로세스 문맥이라는 것을 알 필요가 없지만, 현재의 컴퓨터에서는 Time Sharing / Multitasking 등이 실행되기 때문에, CPU가 프로세스들 간에 계속 전환되고 변환되게 된다. 따라서, 해당 프로세스에 대한 값을 백업해놓지 않으면, 처음부터 다시 실행해야 하는 문제들이 생길 수 있다.
2. 프로세스의 상태 (Process State)
- 프로세스는 상태(state)가 변경되며 수행된다.
* 컴퓨터 내부에 cpu는 하나씩 밖에 없다고 가정
1) Running
- CPU를 잡고 명령어를 수행중인 상태
2) Ready
- CPU를 기다리는 상태 (메모리 등 다른 조건을 모두 만족)
* 일반적으로는, 이 상태에 있는 프로세스들이 번갈아가면서 CPU를 잡았다 놨다 하며, Time sharing을 구현하고 있음.
3) Blocked (= wait = sleep)
- CPU를 주어도 당장 명령어를 수행할 수 없는 상태
- 프로세스 자신이 요청한 event(ex. I/O)가 즉시 만족되지 않아, 이를 기다리는 상태
ex. Disk에서 file을 읽어와야 하는 경우, 명령어 실행에 필요한 부분이 메모리에 올라와있지 않은 상태
4) New
- 프로세스가 생성중인 상태
5) Terminated
- 수행(excution)이 끝난 상태
* 큐 : 선입선출
* 사실 큐라는 것은 운영체제 커널이 Data 영역에, 자료구조로 큐를 만들어놓고 프로세스의 상태를 바꿔가면서(ready상태에는 cpu를 주고, blocked는 cpu를 안주는 식) 운영함.
- 즉 운영체제 커널은 각 프로세스마다 관련된 정보를 관리하기 위해, Data영역에 PCB라는 것을 마련해두고 있다.
3. Process Control Block (PCB)
- 운영체제가 각 프로세스를 관리하기 위해 프로세스당 유지하는 정보
- 다음의 구성요소를 가진다. (구조체로 유지)
1) OS가 관리상 사용하는 정보들
- Process state (프로세스의 상태)
- Process ID (주민번호처럼 id를 지님)
- scheduling information, priority (cpu를 프로세스에 주기 위한 우선순위나 스케줄링 정보 ..)
2) 프로세스의 문맥을 표시하기 위한 정보들 (CPU 수행 관련 하드웨어 값)
- Prgram Counter
- Registers
3) 메모리 관련한 문맥을 표시하기 위한 정보들
- Code / Data / Stack의 위치 정보
4) 이 프로세스가 오픈하고 있는 파일 및 리소스와 관련한 정보들
- Open file descriptors ...
# 이와 같은 것들이 프로세스의 PCB를 구성하고 있으며, 이를 OS가 관리하고 있다.
4. 문맥 교환 (Context Switch)
- CPU를 한 프로세스에서 다른 프로세스로 넘겨주는 과정
- CPU가 다른 프로세스에게 넘어갈 때 운영체제는 다음을 수행한다.
a. CPU를 내어주는 프로세스의 상태를, 그 프로세스의 PCB에 저장한다.
b. CPU를 새롭게 얻는 프로세스의 상태를, PCB에서 읽어온다.
* 프로그램의 처음부터 다시 실행하는게 아니라, 시점의 문맥을 기억해 그 부분부터 시작할 수 있도록 돕는 메커니즘임.
- System call이나 interrupt 발생 시, 반드시 문맥 교환(Context Switch)가 발생하는 것은 아니다.
1) 문맥 교환(Context Switch) 발생 X
: 프로세스가 System call, interrupt로 인해, os커널로 cpu 제어권이 넘어가지만, 다시 해당 프로세스로 돌아오는 경우
* 이는 문맥교환이라고 하기에는 어려움이 있음. 약간의 문맥은 Save가 되지만, 프로세스가 자체가 바뀌는 것에 비해 오버헤드가 적기 때문.
2) 문맥 교환(Context Switch) 발생 O
: 프로세스가 I/O 요청 System call, Timter interrupt로 인해, os 커널로 cpu 제어권이 넘어가고, 다른 사용자 프로세스로 넘어가는 경우
- 특히 이는 캐시 메모리 부분에서 차이가 있음. 문맥교환이 이루어지게 되면, 2)와 같이 다른 프로세스로 이동하기 위해 캐시 메모리를 모두 삭제(flush)해 버려야 하나, 1)과 같은 경우에는 캐시 메모리를 모두 지워버릴 필요가 없음. cpu context의 어느 정도만 save했다가 다시 복원함.
5. 프로세스를 스케줄링 하기 위한 큐
1) Job queue
- 현재 시스템 내에 있는 모든 프로세스의 집합
2) Ready queue
- 현재 메모리 내에 있으면서, CPU를 잡아서 실행되기를 기다리는 프로세스의 집합. 즉, CPU를 기다리는 큐.
3) Device queue
- I/O device의 처리를 기다리는 프로세스의 집합
# 프로세스들은 각 큐들을 오가며 수행된다.
* 프로세스가 자식 프로세스를 만들기도 하는데, 자식 프로세스가 실행중인 동안에 ready queue에 놓기도 함.
6. 스케줄러 (Schedular)
- 스케줄러 : 순서를 정해주는 것
1) Short-term schedular (CPU 스케줄러 or 단기 스케줄러)
- 굉장히 짧은 시간 단위로 Scedular가 일어나는 것. (millisecond 단위)
- 어떤 프로세스를 다음번에 running 시킬지(CPU를 줄지) 결정
2) Long-term schedular (job 스케줄러 or 장기 스케줄러)
- 프로세스에 메모리 및 각종자원들을 어떤 프로세스에게 줄지를 결정하는 문제
- 시작 프로세스(new) 중 어떤 것들을 ready queue로 보낼지(admitted) 결정
- degree of Multiprogramming을 제어
* 메모리에 몇 개의 프로그램이 올라갈 수 있을지에 대해 조정하는 것이 중요한 이슈 (너무 많아도, 적어도 좋지 X)
- 우리가 사용하는 시스템, 즉 time sharing system에는 보통 장기 스케줄러가 없음 (무조건 ready)
* 무조건 ready가 되는 시스템들을 메모리에서 조정하기 위해 나타난 스케줄러가 바로, Medium-term schedular
3) Medium-term schedular (Swapper or 중기 스케줄러)
- 프로세스가 시작되면 무조건 메모리는 주지만, 너무 많은 프로그램이 동시에 메모리에 올라갈 경우, 여유 공간 마련을 위해 일부 프로세스를 통째로 메모리에서 디스크로 쫓아냄
- 즉, 프로세스에게서 memory를 뺏는 문제를 다룸
- degree of Multiprogramming을 제어
# 현재의 컴퓨터가 Medium-term schedular이기 때문에, 현재의 운영체제(OS)에서는 앞서 얘기했던 프로세스의 상태에서 한가지가 더 추가됨.
1) Running
- CPU를 잡고 명령어를 수행중인 상태
2) Ready
- CPU를 기다리는 상태 (메모리 등 다른 조건을 모두 만족)
* 일반적으로는, 이 상태에 있는 프로세스들이 번갈아가면서 CPU를 잡았다 놨다 하며, Time sharing을 구현하고 있음.
3) Blocked (= wait = sleep)
- CPU를 주어도 당장 명령어를 수행할 수 없는 상태
- 프로세스 자신이 요청한 event(ex. I/O)가 즉시 만족되지 않아, 이를 기다리는 상태
ex. Disk에서 file을 읽어와야 하는 경우, 명령어 실행에 필요한 부분이 메모리에 올라와있지 않은 상태
4) New
- 프로세스가 생성중인 상태
5) Terminated
- 수행(excution)이 끝난 상태
6) Suspended (stopped)
- 외부적인 이유로 프로세스의 수행이 정지된 상태
- 프로세스는 통째로 디스크에 swap out 된다.
ex 1. 사용자가 프로그램을 일시 정지시킨 경우 (break key)
ex 2. 시스템이 여러 이유로 프로세스를 잠시 중단시킴 (메모리에 너무 많은 프로세스가 올라왔을 때)
# Blocked와 Suspended의 차이 - Blocked : 자신이 요청한 event가 만족되면 Ready. : 즉, 이는 다른 곳(I/O)에 가서 작업을 하고 있는 상태를 말함. (다른 곳에서 일할 수 있음.) - Suspended : 외부에서 resume해 주어야 Active : 즉, 이는 cpu뿐만 아니라, 외부에서 메모리를 통째로 빼앗아 이 프로세스를 강제로 정지시켜놓은 상태이기 때문에, 다른 곳에서 일을 할 수 없음. |
7. Thread
- Thread (lightweight process)는 CPU를 수행하는 단위를 의미한다.
- Thread의 구성
a. PC(Program Counter)
b. rgister set
c. stack space
- Thread가 동료 Thread와 공유하는 부분 (=task)
a. Code section
b. Data section
c. OS resources
- 따라서, Thread라는 것은 프로세스 하나에서 공유할 수 있는 부분은 최대한 공유하고 (메모리, 각종 자원들), 별도로 CPU 수행에 관련된 정보 (PC, register, stack)과 같은 부분은 각각 가지도록 돕는 것을 의미한다.
* 전통적인 개념의 heavyweight process는, 하나의 Thread를 가직고 있는 task로 볼 수 있다.
1) Thread의 장점
(1) 응답시간이 빨라진다.
- 다중 Thread로 구성된 Task 구조에서는, 하나의 서버 Thread가 blocked(wating)상태인 동안에도 동일한 Task 내에서의 다른 Thread가 실행(running)되어 빠른 처리를 할 수 있다.
ex. 웹브라우저에서 네이버 페이지를 보는 경우 : 네트워크를 통해서 웹페이지를 읽어오는(I/O) 작업을 할 때, 텍스트보다 이미지는 작업 시간이 더 오래 걸릴 것임. 따라서, 모든 웹서버를 불러올 때까지 프로세스를 blocked 시키는 것이 아닌, 이미지 Thread만 bblocked 시켜놓고, 빠른 텍스트 Thread만이라도 먼저 화면에 보여주게 되면, 사용자 입장에서는 응답시간이 빠르다고 느낄 수 있을 것임.
* 이를 동기식 입출력 / 비동기식 입출력 차원에서 보면, I/O를 실행시키는 동안에 프로세스 전체를 blocked시키는 것이 아닌, 다른 Thread를 실행하는 것으로 보아, 일종의 비동기식 입출력이라고 볼 수 있음.
(2) 자원공유를 통해, 처리율이 높아진다.
- 동일한 일을 수행하는 다중 Thread가 협력하여, 높은 처리율(throughput)과 성능 향상을 얻을 수 있다.
cf. 메모리(code, data, stack)와 같은 자원들의 낭비를 절약하고, 효율적으로 쓸 수 있음.
(3) 경제성이 좋아진다.
- 비슷한 프로세스를 하나 더 만드는 것과, 그에 따라 발생하는 context switch는 오버헤드(cpu 관련 정보 저장, 캐시메모리 flush)가 상당히 크게 발생한다. 다중 Thread를 사용하면, 이러한 오버헤드를 상당히 줄일 수 있다.
cf. Solaris OS의 경우, 각각의 프로세스를 생성하는게 각각의 Thread를 만드는 것보다 약 30배정도 더 오버헤드가 발생한다. 따라서 보통은 프로세스를 여러개 만드는 것보다, 다중 Thread를 두는 것이 더 좋다.
(4) 병렬성을 높일 수 있다. (CPU가 2개 이상 있는 컴퓨터에서만 얻을 수 있는 장점임)
- Thread를 사용하면 병렬성을 높일 수 있다.
ex. 1000 x 1000 행렬 연산을 수행하는 경우. cpu가 2개 있으면 서로 다른 cpu에서 실행 후 합쳐 더 빠른 결과를 만들어낼 수 있음.
2) Thread 구현방법
(1) Kernel Threads
- 운영체제 커널에 지원을 받는 Thread 방식
- 즉, Thread가 여러 개 있다는 사실을 운영체제(os) 또한 인지하고 있는 것이다. 따라서 하나의 Thread에서 다른 Thread로 cpu가 넘어갈 경우에도, 커널이 cpu 스케줄링을 하는 것처럼 넘겨주게 된다.
* cpu 스케줄링 : 누구한테 cpu를 나눠줘야 효율적일지 구성하는 것
(2) User Thread
- 프로세스의 라이브러리 형태로 구현하고 있는 Thread 방식
- 즉, Thread가 여러개 있다는 사실을, 운영체제(os)는 인지하지 못하고 있는 것이다.
- 이는 User 프로그램이 스스로 여러개의 Thread를 관리하는 것이며, 다시 말해 프로세스 본인이 내부에서 cpu 수행단위를 여러 개 두면서 관리하는 것이다.
- 따라서 약간의 구현상의 제약점들이 존재할 수 있다.
(3) real-time Threads
- real-time(실시간) 기능을 지원하는 Thread들도 생성할 수 있다.
* 유의사항 - 아직 공부하고 있는 문과생 코린이가, 정리해서 남겨놓은 정리 및 필기노트입니다. - 정확하지 않거나, 틀린 점이 있을 수 있으니, 유의해서 봐주시면 감사하겠습니다. - 혹시 잘못된 점을 발견하셨다면, 댓글로 친절하게 남겨주시면 감사하겠습니다 :) |