시스템 프로그래밍(4)

조권휘·2022년 8월 20일
0

시스템 프로그래밍

목록 보기
4/14

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
profile
안녕하세요 :) Data/AI 공부 중인 한국외대 컴퓨터공학부 조권휘입니다.

0개의 댓글