여기부터 3장
2장에서 제일 중요한 건 System call
Process
실행 중인 프로그램: 디스크에 있는 프로그램 + 프로그램 실행을 위한 resource들
Ex) 메모리: Stack, Heap, Text section, Program counter, Data section(전역변수 저장)...
Text: 프로그램 코드
Data: (초기화된)전역변수, 정적 변수 (bss: 초기화되지 않은 전역변수)
Heap: 동적 메모리
Stack: 지역변수나 etc
Time shared 에서 관리하는 기본 단위
I/O Bound Process: I/O 작업을 많이 하는 프로세스
CPU-Bound process: CPU 작업을 많이 하는 프로세스
실행하는 동안 종료 시까지 자신의 상태를 변화시킨다.
- new: 프로세스가 만들어지는 중
- running: 명령어 실행 중
- waiting: 작업 대기
- ready: CPU 할당 대기 (Ready queue에 들어간 상태)
- terminated: 종료
< 교수님피셜) 이 그림 중요함 >
scheduler dispatch: 스케줄러가 CPU 할당
프로세스는 위 5가지 상태에서 변이하며 실행한다
PCB(Process Control Block)
프로세스와 관련된 모든 정보는 PCB에 저장된다.
- 현재 State, 다음 실행할 명령어 주소(Program counter) 등
* MMU: Logical address space -> Physical address space 변환 (Page table, Segmentation table)
나중에 배울 거임
<교수님피셜) 이 그림 중요함>
여러 개의 프로세스를 메모리에 올린 후 한 프로세스가 CPU를 사용하다가
I/O 작업을 하게 되거나 time quantum이 끝나면 다른 프로세스에 CPU를 할당해준다.
위 그림이 그 과정.
이 작업은 다음과 같이 이루어진다.
① $P_0$의 정보를 $P_0$의 PCB($PCB_0$)에 저장한다.
② $P_1$의 작업을 시작해야 하므로 $PCB_1$의 모든 정보(Program counter, Register 값, ...)를 읽어온다.
③ $P_1$ 실행
④ 현재 $P_1$의 상태를 $PCB_1$에 저장한다.
⑤ $PCB_0$의 모든 정보를 읽어온다.
⑥ $P_0$을 실행한다.
이런 작업을 Context switch라 한다.
Process scheduling
Process scheduler는 CPU를 할당할 프로세스를 선택한다.
이 때 선택시간은 아주 짧아야 한다.
-> Scheduling queue
OS는 다양한 Scheduling queue를 관리한다.
- Job queue: 메모리에 올라갈 준비가 된 작업
- Ready queue: CPU를 할당받을 준비가 된 프로세스
- Device queue: 각 Device마다 존재, 그 Device를 액세스 하려고 하는 프로세스
프로세스는 여러 상태를 전이하며 실행된다 -> 여러가지 scheduling queue를 전이하며 실행된다.
프로세스 생성: new
CPU를 할당받을 준비: Ready queue (State: ready)
CPU 할당받음: (State: running)
Disk로부터 데이터 요청: waiting state(해당하는 device의 device queue에서 대기)
데이터 받음: waiting state 종료, running state로 전환
할당 시간 만료: Ready state로 전환, Ready queue로 전환
fork: 생성된 Child process 역시 다른 프로세스처럼 ready queue로 들어가 ready state가 됨
interrupt 대기: waiting statewaiting state에서
interrupt: ready queue로 이동 (ready state)
Scheduler
- Short-term schduler(CPU scheduler)
ready queue에 있는 프로세스 중 어느 프로세스에 CPU를 할당할까? -> 빈번하게 동작: short-term(수 ms 안에 호출)
- Long-term Scheduler(Job schduler)
사용자가 제출한 job 중 어느 job을 ready queue에 올릴까? 수 s, minute 안에 호출
멀티프로그래밍의 정도를 이 스케줄러가 결정함
이 스케줄러가 I/O-bound process와 CPU-bound process를 잘 섞어서 올려야
두 장치를 모두 바쁘게 할 수 있다(둘 중 하나만 올리면 두 장치 중 하나는 놀게 되니까).
즉 process mix를 잘 해야 한다.
- Medium-term scheduler
Swapping: 큰 프로세스 실행 시 가용 메모리가 모자랄 경우 이미 할당된 프로세스를 디스크로 옮기고 그 공간을 큰 프로세스에게 할당하는 것
어느 프로세스를 swap out(Memory -> Disk)하고 어느 프로세스를 swap in(Disk -> Memory)할 것인가?
-> Medium-term scheduler가 결정
Context switch
<교수님피셜) 이거 중요함?>
$A$라는 프로세스와, $B$라는 프로세스가 있다고 하자.
$A$를 실행하고 있다가 $B$로 CPU 할당이 바뀌면 $A$가 실행되고 있던 context를 $PCB_A$에 저장하고,
$PCB_B$에 있던 context를 이용해 $B$를 실행한다. = context가 바뀐다
이 작업이 없으면 두 프로세스를 동시에 실행할 수 없음
Context switch에 걸리는 시간은 순수한 overhead다
: 이 시간동안은 A의 작업이나 B의 작업이 이루어지지 않는다. -> 짧을수록 좋다
Multitasking 또는 Multiprogramming을 위해 지불해야 하는 비용이라고 보면 될 듯.
어느 부분은 process에 관계 없이 기계적으로 할 수 있고, 어느 부분은 프로세스에 따라 달라진다.
전자의 경우 하드웨어로 구현하면 빠르게 수행할 수 있다. Ex) ARM processoe
하드웨어로 처리하는 부분이 많을수록 빨라지지만, flexibility가 떨어진다는 단점이 있다.
Process Opreation
프로세스 생성(Creation)
프로세스 종료(Termination)
우선순위(Priority) 설정/얻기
Get ID
Get PCB
Process creation
프로세스 $A$에서 프로세스 $B$를 생성하면 $A$는 Parent process, $B$는 Child process.
일반적으로 각 프로세스는 프로세스 ID(PID, Process IDentifier)로 구분 및 관리된다.
부모가 자식을 만들고, 자식이 또 자식을 만드는 트리 구조
Option
- 부모 프로세스와 자식 프로세스는 자원을
ⓐ 공유할 것인가?
ⓑ 일부만 공유할 것인가,
ⓒ 공유하지 않을 것인가?
- 부모 프로세스는
ⓐ 자식과 같이(concurrently) 실행할 것인가?
ⓑ 자식 실행이 끝났을 때만 실행할 것인가?
- 부모와 자식은
ⓐ 같은 메모리 내용을 가질 것인가?
ⓑ 전혀 다른 내용을 메모리에 올려 실행할 것인가?
Process termination
exit(System call): 부모에서 호출해 자식 실행이 끝날 때까지 기다리려면 wait을 호출
wait을 호출하면 exit의 반환값을 전달할 수 있게 된다
exit 해서 종료되면 그 프로세스의 자원은 모두 release돼서 다른 프로세스에 할당할 수 있게 됨
abort: 부모가 자식 프로세스의 실행 종료시킴
부모 종료 시 그 부모가 생성한 자식까지 종료시키는 OS도 있음(Cascaded termination)
IPC(Inter-Process Communication)
프로세스 간에 데이터를 주고받는 방법.
Web server처럼 복잡한 프로그램의 경우 단일 프로세스로 문제를 해결할 수 없을 수 있다.
* 왜 다중 프로세스인가?
속도 상승
프로세스 간 정보 공유
기능 별로 프로세스를 나눠서 구현 -> 전체 SW가 modular하게 구현됨
IPC의 대표적인 경우가 Shared memory, Message passing
Shared Memory
$A$와 $B$가 공통으로 사용하는 메모리 영역을 정한 후 그 영역에 $A$가 값을 쓰고 $B$가 읽는다.
* Producer-Consumer problem
Producer 프로세스는 어떤 작업을 만들어 내고, Consumer 프로세스는 그 작업을 가져와 부가적인 작업을 수행한다.
-> 둘 사이에는 Queue(Buffer)가 존재해 Producer는 이 queue에 쓰고, Consumer는 queue에서 읽어와 후처리를 한다.
이 Buffer는 공유되어야 한다 -> 이 버퍼를 공유 메모리 영역에 저장한다.
이 buffer는 bounded 또는 unbounded로 구현될 수 있다.
Shared buffer는 두 포인터 $in$과 $out$을 갖는 원형 queue로 구성된다.
$in$은 버퍼 내에서 비어 있는 위치(다음 작업이 들어올 위치)를 가리키고,
$out$은 첫번째로 채워져 있는 위치(다음 빠질 작업의 위치)를 가리킨다.
각각 원형 queue에서 $front$와 $rear$의 역할을 한다고 보면 된다.
즉 버퍼가 비어 있으면 $in\,==\,out$이고 버퍼가 가득 차 있으면 $((in+1)%BUFFER\_SIZE)\,==\,out$이다.
따라서 최대 $BUFFER\_SIZE-1$개의 작업만 저장할 수 있다.
이 방식에서는 동기화(Synchronization) 문제가 존재한다
= Producer와 Consumer가 동시에(concurrently) Shared data를 write할 경우 문제가 발생한다(데이터가 '깨진다').
Message passing
프로세스 $A$와 $B$가 $M$이라는 데이터를 주고받는다고 하자.
A -(M)-> 커널 -(M)-> B
$send(msg)$
$receive(msg)$
이 때 $message size$는 고정일 수도, 가변적일 수도 있다.
Producer(이하 $P$)와 Consumer(이하 $C$)가 communicate 하려면 둘 사이의 link가 성립되어야 한다.
-> Implementation note follows as:
언제 link가 수립되는가?
여러 개의 $P(P_1,\; P_2,\; \cdots,\; P_n)$와 여러 개의 $Q(Q_1,\; Q_2,\;, \cdots,\; Q_k)$가 하나의 link를 공유할 수 있는가?
두 프로세스 사이에는 link가 몇 개까지 성립될 수 있는가?
한 번에 메시지를 얼만큼 보낼 수있는가?
메시지의 크기는 가변적으로 할 것인가, 고정으로 할 것인가?
link 하나로 주고받을 것인가(양방향), 받는 link와 주는 link를 별개로 한 것인가(단방향)?
데이터를 주고받는 방식에는 Direct communication과 Indirect communication 방식의 두 가지가 있다.
Direct communictaion
데이터를 주는/받는 프로세스를 명시한다.
$send(P, message)$: $P$에게 보낸다
$receive(Q, message)$: $Q$에게서 받는다.
-> API 호출 시 링크가 자동으로 수립된다.
링크는 정확히 두 프로세스로 연결된다
링크는 구현에 따라 양방향일 수도, 단방향일 수도 있다.
Indirect communication
Mailbox라는 중간 매개체를 통해 보낸다.
각 메일박스는 ID를 가지며 메일박스를 공유한 프로세스끼리만 데이터를 주고받는다.
-> 메일박스를 공유하면 링크가 수립된다.
여러 개의 프로세스가 동일한 메일박스를 공유하면 여러 개의 링크가 수립될 수 있으며
단방향으로 구현될 수도 있고 양방향으로 구현될 수도 있다.
- Opreation
ⓐ Create/Destroy mailbox
ⓑ send/receive through mailbox -> $send(MAILBOX, message),\; receive(MAILBOX, message)$
- Design choice
$P_1,\;P_2,\; P_3$가 메일박스 $M$을 공유하고 있다고 하자.
$P_1$이 보내는 메시지는 $P_2$가 받을까, $P_3$이 받을까? 아니면 둘 다 받을까?
-> 구현에 따라 달라짐
Synchronazation
- Blocking(Synchronous)
데이터를 보내는 프로세스는 받는 프로세스가 받을 때까지 기다린다.
받는 프로세스 역시 받을 때까지 기다린다.
- Non-blocking(Asynchronous)
데이터를 보내는 프로세스는 받는 프로세스가 데이터를 받지 않아도 동작을 끝내고
받는 프로세스 역시 데이터를 못 받아도 동작이 끝난다.
Buffering
메시지를 받는 프로세스가 받는 속도보다 메시지를 주는 속도가 빠르면 queue에 메시지가 저장된다.
-> Queue에 얼마나 저장할 것인가?
- Zero capacity
받는 프로세스가 받을 때까지 줄 수 없다 (Sender는 반드시 Receiver를 기다린다 - rendezvous)
- Bounded capacity (finite length))
Queue가 꽉 차있으면 받는 프로세스가 받을 때까지 줄 수 없다(Sender는 Queue가 꽉 차있으면 기다린다)
- Unbounded capacity(Infinite length)
그냥 준다(Sender가 기다리지 않는다)
* 기다린다 = blocked
Communicatios in Client-Server Systems
Socket
IP와 port으로 구분되는 통신의 endpoint.
직접 IP와 port를 이용해, 주는 소켓과 받는 소켓 간 링크를 수립한 후 Byte stream을 통해 데이터를 주고받는다.
소켓은 구조화되지 않은 바이트스트림만으로 통신하기 때문에 이런 원시적인 데이터를 구조화+해석하는 것은
클라이언트와 서버(각 소켓)의 몫이 된다. -> 비효율적
Remote Procedure call
함수 call처럼 데이터를 주고받는다
프로세스 $P$와 $Q$가 있다 하자.
$P$는 로컬에 있는 함수를 호출하듯이 $Q$를 호출하고, 원격지에 있는 함수가 호출돼서 해당하는 작업이 수행
중간에 proxy가 있어서 이 proxy가 네트워크를 통해 원격지에 있는 함수를 호출하게 된다.
이 클라이언트 쪽(Client-side stub)에서는 marshallling을 해야 한다.
$P$는 Unix에서 동작하고, $Q$는 Inix라는 운영체제에서 동작한다고 하자.
-> 둘의 Computer archiutecture가 다르다.
$P$는 Big-Endian 방식이면서 int형이 4바이트고 $Q$는 Little-Endian 방식이면서 64바이트라면
둘을 일치시켜야 한다.
이 일치시키는 작업이 marshalling이다.
서버쪽에도 이런 stub(Server-side stub)가 있다.
서버에는 서버에서 제공하는 어떤 함수들이 있고 그 함수들을 원격지 클라이언트 쪽에서 호출하게 되는 것이다.
그러면 서버에서 제공하는 함수에 어떤 것들이 있고 어떤 파라미터를 제공해야 되는지를 MIDL(Microsoft Interface Definition Language, XML같은 언어)을 통해 서술할 수 있다. 이 MIDL을 컴파일하면 스켈레톤 코드가 만들어진다.
Server는 MIDL을 이용해 어떤 함수의 formal prototype을 선언
Compiler는 prototype을 그 함수에 대한 skeleton code로 변환
-> Server는 함수의 body만 구현하면 ㅇㅋ
Client가 MIDL로 만들어진 걸 컴파일러로 호출하면 header file(어떤 함수를 어떻게 호출해야하는가)이 만들어짐
그에 맞게 호출만 하면 호출한 내용이 stub에 의해 필요한 data format으로 변환돼서 해당하는 server로 metadata를 주게 됨
Skeleton은 이 metadata를 서버에 맞게 변환해서 사용하게 됨
stub와 skeleton은 RPC를 제공하는 플랫폼에서 컴파일러가 만들어줌
-> 우리는 body만 채우면 ㅇㅋ
Pipes
Java에서의 stream이라 보면 됨
stream을 보내는 도구
- 양방향, 단방향 가능
- 반이중, 전이중 가능
반이중(Half duplex: 한 순간에 한 방향 전송만 가능)
전이중(Full duplex: 동시에 양방향 전송 가능)
네트워크 간 통신, 같은 machine 내 통신 둘 다 가능
- Ordinary pipes
두 프로세스가 데이터를 주고받기 위한 대표적인 방법
단방향: 주는 파이프, 받는 파이프 따로 사용
파이프를 생성한 프로세스가 종료되면 파이프도 존재하지 않게 됨
- Name pipes
Mailbox처럼 데이터를 주고받을 수 있게 해주는 매개체
Linux의 경우 file의 형태로 제공
Message passing vs. Pipes
Message passing: 이미 message format이 고정되어 있어서 그 format에 따라 message를 주고받음
Pipes: 비트 스트림을 주고 받는 쪽에서 원하는 대로 재구성
Summary
Process: 실행 중인 프로그램, 문맥은 PCB에 저장
Process states: 프로세스는 생성부터 소멸까지 이벤트에 의해 상태가 전이되며 실행된다
Context switch: 프로세스에서 다른 프로세스로 전환, 순수 overhead
Schduling: 프로세스 대기 - Job queue, Ready queue, Device queue
Short-term scheduler: 누구에게 CPU를 할당할 것인가
Long-term scheduler: 어느 job을 메모리에 올릴 것인가 - Process mix
Medium-term scheduler: Swapping - 어느 프로세스를 swap in/out 할 것인가
IPC: Message passing / Shared memory / Socket, RPC, Pipes
'강의노트 > 운영체제' 카테고리의 다른 글
[운영체제] 3주차: Review (1) (0) | 2021.03.22 |
---|---|
[운영체제] 2주차 (3) (0) | 2021.03.14 |
[운영체제] 2주차 (1) (0) | 2021.03.12 |
[운영체제] 1주차 (3) (0) | 2021.03.08 |
[운영체제] 1주차 (2) (0) | 2021.03.07 |