출처 : KMOOC / 운영체제 / 이화여대 반효경 교수님


예를 들어 프로세스 B가 가상으로 0~32의 주소를 갖고 있다고 하자.
메모리에서 16만큼만 쓸 수 있다고 하자.
0~16을 잘라서 물리 주소 ? ~ ?+16에 올린다.
이 과정에서 가상 주소 → 물리 주소 번역이 필요하다.
남은 16~32는 스왑 영역에 보관한다.


프로세스의 개념

프로세스 : 실행중인 프로그램
프로세스의 문맥(context)
- 프로세스의 과거 정보와 현재 상태를 의미
- ex) 하드웨어 문맥 : CPU에서 얼만큼 수행했는가 ex) Program Counter, 각종 register
- ex) 프로세스의 주소 공간 : code, data, stack
- ex) 프로세스를 관리하기 위한 커널 내 자료 구조 : PCB, Kernel stack
프로세스의 상태



PCB

문맥 교환

왜 PCB에 프로세스의 문맥을 따로 저장?
- CPU의 제어권이 프로세스 A에서 프로세스 B로 넘어가면 CPU에서는 프로세스 A의 문맥이 사라지게 됨
- PCB에 프로세스 A의 문맥을 저장해줘야 한다
- 다시 프로세스 A 사용할 때 운영체제가 프로세스 A를 담당하는 PCB를 CPU에 복원시켜주고 제어권을 넘긴다

(1) 단순히 user mode -> kernel mode -> user mode 과정에서 물론 커널도 레지스터 써야 하기 때문에 문맥을 저장하긴 해야 되는데 극히 일부만 저장하면 돼서 비용이 작다
(2) 프로세스 A가 쓰던 캐시 메모리를 전부 지워야해서 비용이 크다
프로세스 스케줄링



스케줄러

스케줄러
- 운영체제에서 스케줄링을 하는 코드
장기 스케줄러
- 우리가 쓰는 time sharing system에는 장기 스케줄러가 없다
- 허락을 받은 프로그램만 메모리에 올라간다
중기 스케줄러
- 우리가 쓰는 time sharing system은 중기 스케줄러를 가진다
- 시작된 프로그램은 일단 메모리에 들어오고 메모리가 너무 차서 성능이 안나오면 특정 프로세스를 통째로 쫓아낸다


중기 스케줄러가 추가되면서 suspended (stopped) 상태가 추가
suspended
- 중기 스케줄러에 의해 쫓겨나거나 사용자가 프로세스 정지하는 등 외부적인 이유로 수행이 정지된 상태
- 외부에서 개입을 해줘야 다시 사용 가능
- 메모리에 없어서 CPU 작업은 더이상 못하지만 I/O 작업은 계속 할 수 있다
running (user mode)
- 프로세스 자신의 코드가 수행중인 상태
running (monitor mode)
- 운영체제가 주도권이 넘어갔더라도 임시적일 경우 비록 운영체제가 CPU를 점유하는 상태지만 운영체제가 running 중이 아니라 프로세스가 running 중이라고 표현
- 즉, 잠시 커널의 코드가 수행중인 상태
- ex) 다른 프로세스의 I/O 작업이 끝나서 인터럽트 들어온다 → 운영체제한테 주도권만 뺏긴 상태고 여전히 running 중인 것으로 취급
Thread



- 같은 프로그램을 여러번 실행 할 때 각각을 다 프로세스로 만들면 비효율적
- 프로세스는 하나만 만들고 PC, 레지스터, 스택만 쓰레드 각각이 따로 보유하고 다른 부분(task)는 공유한다.
A 쓰레드 → B 쓰레드 : 문맥 교환이 일어나지 않아 빠름
A 프로세스 → B 프로세스 : 문맥 교환이 일어나 느림


- 예를 들어, 웹 브라우저에서 웹 페이지 받아올 때 이미지 받아오는 쓰레드가 대기중이더라도 텍스트 받아오는 쓰레드는 실행
- multi-processor에서 thread 여러 개를 둬서 병렬 작업을 시킬 수 있고 그런 효과도 있음

커널 쓰레드
- 운영체제가 존재를 알고 있는 쓰레드
유저 쓰레드
- 운영체제가 존재를 모르는 쓰레드
- 운영체제 입장에선 프로세스 하나지만 내부적으로 쓰레드로 구현
- ex) A쓰레드가 I/O 요청하면 비동기식 입출력 요청하고 제어권을 바로 다시 받아서 B쓰레드 동작한다던지
프로세스 생성과 종료

원칙적으로는 자식 프로세스를 만들면 부모 자식은 독립적인 프로세스
예외적으로 자원을 공유하거나 대기하거나 이런 모델들도 있다

프로세스가 만들어질 때는 일단 부모 프로세스를 그대로 복제하고 거기에 새로운 프로그램을 덮어 씌우는 구조

항상 자식 프로세스가 먼저 종료되고 부모 프로세스가 그 뒷처리를 한다는 원칙
두 가지 경우가 있다
1. 자식 프로세스가 자발적으로 종료(exit)될 때는 부모 프로세스에게 자식 프로세스의 종료 사실을 통보
2. 부모 프로세스가 강제로 자식 프로세스를 종료(abort)하는 경우
→ 부모 프로세스가 자발적 종료하는 경우에도 자식 프로세스부터 밑에서부터 위로 종료시킨다


fork()를 하는 순간 프로세스가 복제된다

부모 프로세스는 자식 프로세스의 pid를 반환받는다
자식 프로세스는 0을 반환받는다
둘 다 문맥이 같기 때문에 if문부터 실행

자식 프로세스에 새로운 프로그램을 덮어 씌우려면 execlp(~) 실행

- execlp(~) 하는 순간 새로운 프로그램이 덮어 씌워짐
- 1번째 print문은 프로그램 덮어씌워지기 전에 수행되니까 출력
- 2번째 print문은 아예 사라지기 때문에 수행되지 않음

- 즉, I/O를 기다리는 blocked 상태 외에 자식 프로세스의 종료를 기다리는 blocked 상태도 있음
- ex) 리눅스에서 vi 켜고 편집(자식 프로세스)하는 동안 새로운 커맨드 입력(부모 프로세스) 불가능

프로세스 간 협력


- 일반적으로 서로 주소를 모르기 때문에 직접적으로 협력은 불가능 / 커널을 통해 협력
- 주소를 공유할 경우 직접적으로 협력 가능 / 하지만 주소를 공유하려면 시스템 콜을 통해 OS에게 부탁해야함
'CS > 운영체제' 카테고리의 다른 글
Process Synchronization II (0) | 2022.05.14 |
---|---|
Process Synchronization I (0) | 2022.05.14 |
CPU 스케줄링 (0) | 2022.05.14 |
컴퓨터 시스템의 구조 (0) | 2022.05.08 |
운영체제 개요 (0) | 2022.05.08 |