Concurrent Processes
- 동시에 실행(병행)되는 여러개의 process
- IPC(Inter Process Communication)을 통해 병행한다.
- 여러개의 process가 하나의 목적을 가지고 일을 나눠 진행하는 program
server process : 정보를 제공하는 process
client process : 정보를 요청하는 process
P2P model : 각자가 server와 client가 동시에 되는 모델
Process & PID
- process : OS 내의 자신의 주소 공간을 가지고 실행되는 program 단위
- process가 실행되면 모든 process는 OS로부터 PID를 받는다.
- PID는 양수이며 재사용이 가능하다.
- 일반적으로 PID0 = OS scheduler / PID1 = init process(모든 process의 조상) / PID2 = pagedaemon
- 모든 process는 PID와 함께 PCB(Process Control Block)도 할당받는다.
- PCB : PID, UID, GID, 현재 사용중인 directory, terminal, priority, memory map 등 모든 정보를 담고 있다.
System calls for PIDs
#include <unistd.h>
pid_t getpid(void);
// Returns: process ID of calling process
pid_t getppid(void);
// Returns: parent process ID of calling process
uid_t getuid(void);
// Returns: real user ID of calling process
uid_t geteuid(void);
// Returns: effective user ID of calling process
gid_t getgid(void);
// Returns: real group ID of calling process
gid_t getegid(void);
// Returns: effective group ID of calling process
Process Creation
#include <unistd.h>
pid_t fork(void);


- 새로운 process를 만드는 함수
- 자신과 똑같은 clone(복제)을 만든다 → child
- 실제로는 다른 process이다. PID, PCB, data, heap, stack 등이 다르다.
- return : 성공 시 생성된 child PID, child에서는 return 0 / 실패 시 -1
- 자식에게 text, uid, dir 정보, r/w offset, FDT 등 모든 자원을 상속한다.
- 자식이 받는 fork()의 return 값은 0이다.
- 즉, return 값 > 0 : parent / return == 0 : child
- text는 같아서 공간을 공유하지만, data / heap / stack은 바꿀 수도 있으니 개별 공간을 사용한다.
- child process는 fork()함수부터 진행된다.
fork()가 실패하는 경우

- 시스템의 memory가 부족해서 process를 열지 못하는 경우(너무 많은 process가 있는 경우)
- 각 user마다 total process를 넘었을 경우 (CHILD_MAX)
Terminating Process
- 1) main 함수에서 return이 실행된 경우
- 2) exit() 함수를 호출한 경우
- 3) process의 마지막 thread가 pthread_exit 함수를 호출한 경우
#include <stdlib.h>
void exit(int status);
- program이 종료될 때 알려주는 함수
- OS를 거쳐 process의 parent에게 status(~~한 상태)를 전달
- parent는 wait()을 이용하여 status를 확인한다.
- main 함수의 return 0, 1..과 동일하다.
- Linux에서는 terminated process(status를 전달하지 않고 종료한 process)를 "zombie process"라고 한다.
- parent가 wait()을 이용하여 exit status를 확인하면 그 때 완전 종료된다.
Waiting Child Process
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
- child 중에 하나가 종료되면 wait()을 통해 status가 전달되고 종료한다.
- status 값이 파악될 때까지 block 된다.
- return : 성공 시 child PID / 실패 시 -1
- waitpid() 함수는 특정 pid를 지정해서 그 process가 종료되면 깨어난다. 즉, return pid와 인자 pid가 같아야한다.
- option : 0 : child가 기다릴 때까지 종료 / WNOHANG : non-blocking으로 바로 반환한다. 주로 parent가 중요한 일을 할 때 사용한다.
- child process가 많을 수 있기 때문에 보통 waitpid()를 많이 사용한다.
Exit Status Macros
- WEXISTATUS(status) : child가 보낸 exit code만 분리
- WIFEXITED(status) : child가 정상적으로 종료되었는지 확인
- WIFSIGNALED(status) : child가 signal에 의해 비정상적으로 종료되었는지 확인
- WIFSTOPPED(status) : child가 현재 멈춰있는지 확인
- WTERMSIG(status) : signal에 의해 종료되었을 때 그 signal의 number를 가져온다.
- WCOREDUMP(status) : 종료된 process의 모든 file을 core-file로 담았는지 확인
exec() System call
#include <unistd.h>
int execl(const char *pathname, const char *arg0, ... /* (char *)0 */ );
int execv(const char *pathname, char *const argv[]);
int execle(const char *pathname, const char *arg0, ... /* (char *)0, char *const envp[] */ );
int execve(const char *pathname, char *const argv[], char *const envp[]);
int execlp(const char *filename, const char *arg0, ... /* (char *)0 */ );
int execvp(const char *filename, char *const argv[]);
int fexecve(int fd, char *const argv[], char *const envp[]);
// All return: -1 on error, no return on success

- 호출하면 지정된 program으로 바뀌는 system call
- 바뀌고 난 뒤의 새로운 program은 main function의 처음부터 실행된다.
- PId, owner, priority, alarm, signal, open file, group, parent-child relationship 등은 변경되지 않는다.
- data, text, heap 등 내용(body)이 바뀐다.
User process tree

- init : 모든 process의 조상
- getty : network로 하는 connection 요구를 기다리는 process
- exec은 같은 program이고 다른 이름이라고 생각
Multitask scheduling

- time이 작으면 program이 동시 진행하는 것 같지만 한 순간에 1개만 동작하고 넘어가는 time sharing 개념
- code가 넘어갔다가 다시 돌아올 때는 멈췄던 곳부터 다시 시작한다.
- 멈췄던 곳(state)을 결국 저장해야하는데, 이는 PCB에 저장이 된다.
- PCB의 register에 state를 저장한 뒤, 돌아오면 PCB를 reload 후 재실행한다.
- 저장된 register 정보는 메모리에 저장되어있다.
Context switching

- process간에 timer interrupt로 전환되는 과정
- 문제점 : interrupt되는 부분을 알 수 없다.
- inconsistent output이 발생하고, race condition이 발생한다.
- race condition : 2개 이상의 process가 공통 자원에 접근할 때 순서에 따라 실행결과가 계속해서 달라지는 상태
Inter Process Communication(IPC)
- problem을 제거하는 communication 방법
1) Sharing files : unstable, low performance
2) Parent - child : race condition 주의
3) message queue : kernel에 message queue를 두고 user가 send, receive 한다.
4) signal : short event
5) pipe : named = any process / unnamed = only parent-child
Pipe

- 2개의 process 사이 IPC 기능
- race condition을 예방할 수 있다.
- OS의 도움을 통해 block / wake up 방식을 사용
- FIFO file : 2개의 r/w offset을 가진다.
- 0 : 오직 read / 1 : 오직 write
- queue로 ring buffer 형태를 가진다.
- mutual exclusion : 한 번에 하나의 process만 접근하도록 한다.
- data가 없으면 read가 block(wait) → block된 pipe는 write할 때 wake up