Process (프로그램 실행)
process는 순차적으로 진행되어야 한다
현재 활동 상태는 program counter 값과 register의 내용으로 표시된다
프로그램 실행은 GUI 마우스 클릭, 명령줄 입력 등을 통해 시작한다
하나의 프로그램은 여러 실행을 할 수 있다. (ex. chrome)
프로세스의 메모리 배치


text, data 영역의 크기는 고정되기 때문에 프로그램 실행시간 동안 크기가 변하지 않는다.
그러나 stack, heap 영역의 크기는 가변적인데, 함수가 호출될 때마다 활성화 기록이 stack에 push되며, 함수에서 제어가 되돌아오면 pop된다.
⇒ stack, heap 구역이 서로의 방향으로 커지더라도 운영체제는 서로 겹치지 않도록 해야한다.
프로세스는 실행되면서 그 상태가 변한다.

다른 실행에 의해 interrupt → ready로 이동
I/O 입력 기다릴때 → waiting으로 이동
각 프로세스와 관련된 정보들을 표현한 블록 (task control block이라고도 불린다.)

<PCB>
Represented by the C structure taks_struct

프로그램이 여러 개의 실행 task를 갖게 하는 방법
CPU에서 실행할 process를 선택하는 것
scheduling의 목적은 CPU 활용을 극대화 하는 것과 사용자가 각각 program과 상호작용할 수 있게 하는 것이다.
Ready queue: 주 메모리에 있는 모든 프로세스의 집합이다. 프로세스가 시스템에 들어가면 ready queue에 들어가서 준비 상태가 되어 CPU 코어에서 실행되기를 기다린다.
Wait queue: 특정 이벤트가 발생하기를 기다리는 프로세스 집합(I/O 요청 완료 같은)

process scheduling의 표현

CPU가 한 프로세스에서 다른 프로세스로 전환한다

최근 모바일 시스템은 사용자 어플리케이션을 위한 멀티태스킹을 제공한다.
안드로이드는 foreground와 background를 실행한다
부모 프로세서는 자식 프로세서를 생성하고, 이는 차례대로 다른 프로세서들을 생성하여 프로세스 트리(tree of process)를 형성한다.
process identifier(pid)를 통해 프로세스를 식별하고 관리한다.
option
Resource sharing options
Execution options
Address space

fork()로 복사본을 만든 다음 execlp()로 복사본의 내용을 새로 덮어씌워서 새로운 프로그램을 만든다
in Linux


프로세스 트리 in 리눅스
fork()#include <unistd.h>
pid_t **fork**(void);
자식 프로세스 생성
calling 프로세스(부모 프로세스)를 복제해서 새 프로세스(자식 프로세스) 생성
자식과 부모 프로세스는 분리된 메모리 공간에서 실행한다
fork()를 하는 시점에 두 메모리 공간은 같은 내용을 갖는다
메모리 작성, 파일 mapping, unmapping는 다른 프로세스에 영향을 주지 않는다
리턴 값 : child 성공 : 0
parent 성공 : child PID
error : -1
자식 프로세스의 리소스
// after // : 공유하지 않음프로세스가 마지막 명령문의 실행을 끝내고, **exit()** 시스템 콜을 사용하여 운영체제에 자신의 삭제를 요청하면 종료한다.
부모는 자식의 실행을 종료할 수 있다
보통의 경우, 부모 프로세스가 종료된 후에 자식 프로세스가 존재할 수가 없다. 이 경우 부모가 종료되면 자식도 연달아 종료되는, 연쇄식 종료작업(cascading termination)이 시행된다.
부모 프로세스는 wait() 시스템 호출을 사용하여 자식 프로세스의 종료를 기다릴 수 있다. 호출은 종료된 프로세스의 상태 정보와 pid를 반환한다.
pid = wait(&status);
zombi
종료되었지만 부모 프로세스가 아직 살아있어서 wait() 호출을 하지 않은 프로세스
자식은 종료됐는데 부모가 아직 안끝난 경우
종료하게 되면 모든 프로세스는 좀비 상태가 되지만 아주 짧은 시간 동안만 머무른다.
orphan
부모 프로세스가 wait()를 호출하지 않고 종료한다면, 자식 프로세스들은 고아(orphan) 프로세스가 된다.
wait()#include <sys/wait.h>
pid_t **wait**(int *wstatus); //ch3_p.31
프로세스가 상태를 바꿀때까지 기다린다
대부분의 최신 웹 브라우저는 단일 프로세스로 실행한다
→ 한 웹 사이트에 문제가 생기면, 전체 브라우저가 충돌한다
Google Chrome 브라우저는 3가지 유형의 프로세스가 있는 multiprocess이다.


시스템 내 프로세스는 독립적이거나 협력적일 수 있다.
프로세스 협렵을 하는 이유
협력적 프로세스는 inter process communication(IPC)가 필요하다.
IPC의 두 가지 모델
공유 메모리 모델에서는 협력 프로세스들에 의해 공유되는 메모리의 영역이 구축된다.
프로세스들 사이에서 소통하기위해 공유된 메모리의 영역
커뮤니케이션은 운영체제가 아닌 사용자의 프로세스의 통제하에 있다.
주요 이슈는 그들이 공유 메모리에 접근할 때 동기화된 action을 취하는 것을 사용자 프로세스가 허락하도록 메커니즘을 제공하는 것이다

생산자와 소비자는 공유 메모리를 통해 정보를 통신한다.
생산자 : 소비자를 위해 정보를 생산한다
소비자 : 생산자가 기록한 정보들을 소비한다
ex) 컴파일러-어셈블러, 서버-클라이언트
⚠️ 생산자-소비자는 동기화(synchronized)되야한다
생산자와 소비자의 공유 메모리에 두 가지 버퍼가 사용되는데, 무한 버퍼(unbounded-buffer)는 크기에 실질적은 한계가 없고 생산자가 항상 생산할 수 있는 반면, 유한 버퍼(bounded-buffer)는 버퍼의 크기가 고정되어 있다고 가정한다. 버퍼가 가득차있다면 생산자는 기다려야한다.
Bounded Buffer
circular queue : 논리구조가 원형인 제한된 크기의 버퍼
마지막 요소 뒤에 첫번째 요소가 온다
BUFFER_SIZE -1 만큼 저장할 수 있다
#define BUFFER_SIZE 6
typedef struct {
. . .
} item;
item buffer[BUFFER_SIZE];
int in = 0; //tail or rear
int out = 0; //head or front
//inserting an item
buffer[in] = newItem;
in = (in + 1) %n;
//extracting an item
item = buffer[out];
out = (out + 1) %n;
//Empty/full condition
in == out : buffer is empty
(in+1)%BUFFER_SIZE == out : buffer is full
cf.buffer는 최대 버퍼 사이즈-1 크기의 값까지 저장할 수 있다.

queue 같음!! 앞에서부터 순차적으로 실행되고, 실행 후 삭제되면 그 다음 값이out(front)이 됨!!
/*shared_memory : 생산자*/
item next_produced;
while(1){
//next_produced 위치에 아이템 생산
while(((in + 1) % BUFFER_SIZE) == out); //full -> waiting
buffer[in] = next_produced;
in = (in + 1) % BUFFER_SIZE;
}
/*소비자*/
item next_produced;
while(1){
//next)produced 위치에 아이템 생산
while(in == out); //empty -> waiting
next_consumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
//consume the item in next_consumed
}
1. 직접/간접 소통
직접 : 연결 링크가 직접 프로세스를 연결한다
간접 : 프로세스가 via mailbox로 연결된다

직접 소통

간접 소통
2. 동기화 (Synchronization)
Message passing은 blocking or non-blocking일 수 있다.
Blocking : 동기식 (wait function)
Non-blocking : 비동기식
sender, receiver 모두 blocking일 경우 : Rendezvous(랑데뷰)
sender는 receiver를 기다려야 한다!!
예시
/*Message Passing : 생산자*/
message next_produced;
while(1){
//next_produced 위치에 생산
send(next_produced);
}
-------------------------------------------------
/*소비자*/
message next_consumed;
while(1){
receive(next_consumed);
// next_consumed에 있는 아이템을 소비한다
}
3. 버퍼링
소통 중에, 메세지는 임시 queue(buffer) 에 저장된다.
send → buffer → receive
버퍼 용량 3종류
POSIX 공유 메모리
파이프는 두 프로세스가 통신할 수 있는 통로 역할을 한다.
Ordinary 파이프
Named 파이프
일반적인 파이프는 일반적인 생산자-소비자에서 한 방향 소통이 가능하다.
Window에서는 익명의 파이프라고 부른다.
ordinary 파이프보다 더 강력하다.
(출처)
Operating System Concepts 도서
https://www.booksfree.org/operating-system-concepts-10th-edition-by-abraham-silberschatz-peter-b-galvin-greg-gagne-pdf/