-
[OS] Process란?개발자 ON/OS 2020. 9. 1. 21:10
이번 글에서는 운영체제에서 필수적인 개념인 Process에 대해 알아보겠다.
먼저 Process란 무엇인가?
- An Instance of a Running Program
- A Program in Execution
즉, 프로세스란 실행 중인 프로그램이다. 프로그램을 저장장치에 저장되어 있는 정적인 개체라고 했을 때, 프로세스는 이러한 프로그램을 메모리로 불러와 CPU에서 실행하기 위한 동적인 개체이다.
Process의 크게 다음과 같은 두 가지 부분으로 구성되어 있다.
1. Images
2. Process Context
간단하게는 Images에는 프로세스 실행에 관한 정보가 담겨있고, Process Context에는 OS가 프로세스를 관리하는데 필요한 정보가 담겨있다.
1. Images
< Images > Images의 자세한 구성은 위 사진과 같다.
1. Command-line arguments / environment variables: 프로그램 실행 시 주어진 커맨드라인 인자나 환경 변수2.
2. Stack: 정적 메모리. 지역변수, Return 주소 등이 저장된다.
3. Heap: Run-time에 동적으로 할당된 메모리로 Stack보다 접근시간이 느리지만 동적으로 배치되기 때문에 크기가 더 크며, 개체 간 의존성이 없기 때문에 랜덤 접근이 가능하다.
4. Uninitialized Data: 초기값이 지정되지 않은 전역 변수
5. Initialized Data: 초기값이 지정된 전역 변수
6. Code: Read-Only Instruction 코드
=>
exec
시스템 콜에 의해 4는 0으로 초기화되고 5번과 6번은 프로그램 파일로부터 정보를 읽어온다.2. Process Context
< Process Context > Process Context는 다음과 같이 구성되어 있다.
1. Program Context
- 범용 레지스터 (Data/General registers)
- 특수 레지스터: Program Counter, Stack Pointer 등
2. Kernel Context
- pid, gid, sid, environment
- VM Structures ( page tables )
- Open Files
- Signal Handlers
=> Program Context는 CPU에서 프로세스 실행을 위한 정보를 가지고 있고 Kernel Context는 OS가 여러 개의 프로세스를 관리하기 위한 데이터로 구성되어 있다.
Process Control Block (PCB) or Process Descriptor (PD)
위 설명과 같은 구성으로 되어 있는 프로세스는 실제로 시스템에서 PCB, 혹은 PD, 라는 데이터 구조로 되어 있다.
< PCB > 추가적인 요소를 설명하자면,
1. Process State: 프로세스가 수행 중인지 대기 상태인지, 준비 상태인지 등을 나타낸다. (아래 추가 설명)
2. CPU-scheduling Information: OS 정책에 따라 어떻게 CPU를 관리할지에 대한 정보 (CPU Scheduling 관련 글 참고)
3. Memory-scheduling Information: OS 정책에 따라 어떻게 메모리를 관리할지에 대한 정보 (Memory Management 관련 글 참고)
4. Accounting Information: CPU 사용량이나, 사용시간, 남은 사용시간, 프로세스 넘버 등의 정보
5. I/O Status Information: 연결되어 있는 I/O 장치나 files에 대한 정보
=> 한마디로 PCB는 프로세스에 대한 모든 정보를 가지고 있는 데이터 구조로 프로세스를 시작하거나 멈추거나 재시작하는데 쓰일 수 있다.
< Linux PCB > 리눅스의 PCB는 task_struct라는 이름으로 되어있으며 실제 구조는 위와 같다. 파란 부분이 Program Context이고 나머지 부분 전체가 Kernel Context일 정도로 PCB에서 Kernel Context가 차지하는 비중이 높다.
Process State
< 다섯 기본 상태 > Process는 동적인 개체로 수행 중 상태가 계속 변한다. 위 사진은 Process의 대표적인 다섯 상태로 실제 OS에 따라 이보다 더 많은 상태가 존재할 수 있음을 인지하자.
1. New: 프로세스가 생성됐을 시의 상태
2. Ready: CPU에 배정되기를 기다리는 상태
3. Running: CPU에서 Fetch-Decode-Execution이 이루어지는 상태
4. Blocked: I/O 나 Timeout 등으로 기다리는 상태
5. Exit: 종료된 상태
=> blocked 된 프로세스는 I/O Controller에 의해 상태가 변할 수 있기 때문에 I/O Controller와 CPU가 병렬적으로 작동한다는 것을 알 수 있다.
< linux state diagram > 위는 리눅스 운영체제의 상태도이며 Running 상태가 두 개로 나뉘는 것을 볼 수 있다. Blocked 상태도 Task_Interruptible과 Task_Uninterruptible 두 상태로 나뉘는데 전자는 I/O나 시그널로 인해 Task가 Interrupt 될 수 있다는 뜻이며 후자는 하드웨어 상태를 직접적으로 기다리는 상태로 Interrupt될 수 없다.
* 리눅스 PCB 이름이 task_struct임에서 알 수 있듯이 리눅스 운영체제에서 Process는 Task와 동치이다.
Process Switching
-> 실행 중인 프로세스가 운영체제에 의해 Interrupt 되고 새로운 프로세스가 Running State를 얻음으로 CPU 자원을 차지하는 것
과정
1. Program Context 저장
2. 현 프로세스 상태 변경: running -> blocked/ready/exit
3. PCB를 적정한 Queue로 이동 i.e. I/OWaitQueue, ReadyQueue
4. 프로세스 스케줄링 정책에 의해 새로운 프로세스 선택
5. 해당 프로세스 PCB 이동
6. 해당 프로세스 상태 변경 ready -> running
7. 메모리 상태 업데이트
8. 새로운 프로세스 Program Context CPU에 복원
Mode Switching
현대의 운영체제는 악의적인 코드가 시스템을 망가트리는 것을 막기 위해 적어도 2가지의 모드로 작동한다.
1. USER MODE
일반적으로 유저들이 사용하는 모드로 제한된 권한을 가진다.
2. KERNEL MODE
메모리와 CPU 레지스터 등 프로세서에 대한 완전한 권한을 가진다.
일반적으로 코드 수행 시 User Mode에서 코드가 작동하다가 필요시 Kernel Mode로 넘어가 민감한 코드 부분이 작동한다. 이를 Mode Switching이라고 부르며 Mode Switching의 과정은 다음과 같다.
1. 원인 발생
a. External Interrupt: Timer , I/O Interrupt...
b. Internal Trap: Page Fault, Invalid Operation...
c. System Call: open(), fork()...
2. 프로세서 상태 저장 (레지스터 정보, 플래그 값 등)
3. PC (Program Counter)를 해당 부분을 수행하기 위한 값으로 변경
4. 커널 모드 진입
=> Process Switching과 Mode Switching 모두 프로세서 상태를 저장해야 하기 때문에 일정한 Overhead가 존재한다. 하지만 과정에서도 알 수 있듯이 Process Switching의 Overhead가 훨씬 크다.
=> Process Swtiching 또한 Kernel Mode에서 이루어지기 때문에 Process Swtiching은 필연적으로 Mode Switching을 동반하지만 반대는 아닐 수도 있다.
Process의 생성
Unix 계열에서 프로세스는 약간 특이한 형태로 생성된다. 부모 프로세스 (Parent Process)가 자식 프로세스 (Child Process)를 생성하며 자식 프로세스가 부모 프로세스를 복제한 후 새로운 프로그램을 불러옴으로써 새로운 프로세스를 생성한다.
이는 실제로 두 가지의 System Call 함수의 조합으로 이루어지는데 이는 fork()와
exec()
이다.fork()
함수를 실행하면 pid (process id)만 다른 새로운 자식 프로세스가 생성되는데, 함수를 사용하면 부모 프로세스에서는fork()
성공 시 자식 프로세스의 pid가, 자식 프로세스에서는 성공 시0
이 반환된다. 실패 시-1
이 반환된다.이후
exec()
함수를 호출하면 새로운 Program Context가 할당된다. 즉 새로운 stack, heap, uninitialized data, initialized data, code 가 생성된다.< fork() + exec() > 위 사진에서 100이라는 pid를 가지고 있던 부모 프로세스가
fork()
System Call을 호출했더니 105라는 pid를 가진 자식 프로세스가 생성되었으며exec()
System Call을 통해 새로운 코드를 불러왔다.Process 종료
프로세스 종료는 마찬가지로 exit() System Call을 통해 이루어지며 아래 사진과 같은 handler를 통해 뒤처리를 해준다.
< exit() Overview >
Process에 대해 간략하게 알아보았다. 위는 기본적인 사실이며 구체적인 구현법은 운영체제마다 상이하다는 것을 알 필요가 있다.
혹시 보완해야 하는 부분 지적해주시면 추가/수정하겠습니다.
[참고] A. Silberschatz, P. Galvin, G. Gagne, Operating System Concept", 10th edition, John Wiley, 2019.
[참고] https://en.wikipedia.org/wiki/Process_(computing)
'개발자 ON > OS' 카테고리의 다른 글
[OS] 운영체제 구현 방법론 (0) 2020.09.01