Concurrent Processes(동시실행 프로세스) (1)
실행 중인 프로그램 시스템은 여러 동적 동시 프로세스(dynamic concurrent processes)로 구성된다.
IPC와의 공동 작업 프로세스의 set
Concurrent process 프로그래밍 툴
• Concurrent languages (Ada, Java, PathPascal, Modula II)
• C, C++,.. concurrent programming 을 위한 system call (Linux, UNIX, Win32 Environment)
Applications (Objectives)
• Networked (or distributed) applications
– 네트워크 앱 : 클라이언트 프로세스, 서버 프로세스
– Distributed 앱 : chess 프로그램, 클라우드 컴퓨팅
• 실시간 애플리케이션(응용프로그램)
– 항공기 제어 : 조종석 디스플레이, 비행 관리
– 미사일 시스템, 자동차 : 많은 센서, 제어 장치, 그리고 여러개의 프로세스들로 서보모터(actuators)가 처리된다.
– 일반적으로 각 센서에 대한 프로세스
• 병령 어플리케이션 : 3D 그래픽스, 많은 CPUs, 많은 병렬 프로세스
– 더 많은 CPUs, GPUs 을 이용하기 위함
• 프로그램 레벨에서의 CPU/IO overlap
– 프로세스가 컴퓨팅을 수행할 때 다른 프로세스가 프로그램에서 I/O를 수행한다.
• 비동기 이벤트 처리
– 여러 입력 소스 처리 : 어떤 디바이스가 먼저 입력을 하는지 알 수 없다.
– 이런 경우, 각 입력 디바이스에 프로세스를 할당함
Process & PID
Process -> 운영체제 내에서 주소 공간을 가지고 운영되는 프로그램
PID -> Process id
모든 프로세스는 고유한 프로세스 ID(PID, 음이 아닌 정수)를 가진다
• ID는 고유하지만 종료 후 재사용됩니다.
• PID 0은 보통 swapper로 알려진 스케줄러입니다.
• PID 1은 보통 init 프로세스이다(boostrap 과정의 마지막에 호출되며 /etc/init 또는 /sbin/init에 위치한다)
• PID 2 는 가상 메모리 시스템의 paging을 지원하는 pagedaemon 이다.
각 프로세스는 자체 PCB(process control block) 를 가진다
• 프로세스에 대한 모든 정보가 포함되어 있다.
– PID, UID, GID, current working directory, terminal, priority, state, CPU usage, memory map, open files and locks, ...
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 in Linux
프로세스 생성. 현재 실행되는 프로세스와 같은 것 생성
#include <unistd.h>
pid_t fork(void)
child process 라는 새로운 프로세스를 만든다.
• child는 parent와 똑같은 clone(copy)이다.
• child는 이 fork() 콜에서 돌아오는 것부터 시작함.(왜?)
포크를 부르는 순간 그 순간 parent는 clone이 되어서 동일하게 복사되기 때문. 즉슨, 현재 실행되는 실행상태 그대로(메모리 등) 복사가 되기 때문에
returns
• parent process 의 new born child process 의 PID
• 0 in the child process
• -1 on error
fork() example
Duplicating the address spaces
Divergence of their execution flow
Parent and Child
child 는 parent process의 copy( or clone)이다. 동일 코드 / 데이터 객체 생성
child 는 fork() 호출 시 부모의 대부분의 리소스를 상속 받는다.
- 같은 text를 공유한다(프로그램 코드와 상수 데이터)
- 실제/유효 user-id, group-id
- 현재 working, root 디렉토리
- tty(stdin, stdout, stderr) 를 포함하는 fork 전에 열린 파일
- fork 전에 parent가 열린 파일들의 r/w offsets를 공유
하지만 실제로, 둘은 다른 프로세스이다.
- 다른 PID, 다른 PCB
- 커널에 의해 독립적으로(동시에) 스케줄되어있다.
- 각각이 개인적인 리소스를 가지고 있다
- 다른 데이터/힙/스택 (fork 할때 copy됨)
fork() 는 fail 할 수 있다.
- 만약 너무 많은 프로세스들이 이미 시스템 안에 있다면
- 만약 이 실제 user ID 의 총 프로세스 수가 시스템 제한을 초과하는 경우(CHILD_MAX)
Terminating a process
#include <stdlib.h>
void exit(int status);
exit() 함수는 부모에게 status를 전송한다
• status는 자식 프로세스가 어떻게 종료되었는지 알려준다.
• parent는 wait() 콜을 통해 status 값을 가져온다.(나중에 나옴)
프로세스는 5가지 방법으로 정상 종료될 수 있다.
• 메인 함수로부터 return 을 실행
• exit() 함수 호출하기
• 프로세스의 마지막 스레드에서 pthread_exit 함수를 호출한다.
커널 코드는 종료된 프로세스에 대해 이런 작업들을 수행
• 코드에 의해 프로세스의 열려있는 descriptor 가 모두 닫힌다.
• 할당된 메모리를 release
cf. 종료된 프로세스는 부모가 wait() 시스템 콜에서 return 될 때까지 시스템에 남는다.
• 리눅스에서는 좀비 프로세스라고 부른다.
Waiting a child process
#include <sys/wait.h>
pid_t wait(int *status);
caller (주로 parent)는 자녀가 종료될 때까지 차단된다.
- 재개되면, child의 PCB를 제거한다
return
- 만약 OK인경우 PID를 종료
- -1 on error
파라미터
- int *status : 상태가 기록되는 가변 주소
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
caller(주로 parent)는 지정된 프로세스(pid)가 종료될 때까지 차단된다
- pid 지정 외에는 wait() 와 동일
- wait()를 waitpid()로 만드는 방법
파라미터
- pid
- if pid > 0이면 프로세스 ID가 pid인 child를 기다림
- if pid == -1 이면 child 프로세스를 기다림. waitpid는 wait 과 동일
- options
- WNOHANG : non-blocking call 을 위함
Macros for exit status
넘겨받은 값이 어떤 정보에 대한 것인지 확인하기 위한 여러 매크로 함수들
WEXISTATUS(status)
• fetch the exit code which the child sends
WIFEXITED(status)
• true if the child terminated normally
WIFSIGNALED(status)
• true if status was child terminated abnormally by a signal
WIFSTOPPED(status)
• true if status was returned for a child that is currently stopped
WTERMSIG(status)
• fetch the signal number that caused the child to be terminated
WCOREDUMP(status)
• true if a core file or the terminated process was generated
wait() and exit() example
exec() system call
현재 프로세스를 다른 프로세스로 대체
프로세스가 exec 함수중 하나를 호출하면, 해당 프로세스가 새 프로그램으로 완전히 대체된다.
- 새로운 프로그램은 메인 함수에서 실행되기 시작한다
- exec 전체에서 PID가 변경되지 않음
- exec는 현재 프로세스(text, data, heap, and stack segment)를 치환하기만 하면 됨.
프로그램 body가 변경되었지만 다음의 항목들은 남아있다
- priority
- 프로세스 ID( 같은 프로세스), 작업 디렉토리
- alarm 까지 남은 시간
- pending signals(보류신호)
- 파일과 파일 잠금 열기
exec family
execl
execv
#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
Difference
문자
• v in its name, argv’s are a vector: const * char argv[]
• l in its name, argv’s are a list: const * char arg0, ...
• e in its name, 환경변수를 취한다: char * const envp[]
• p in its name, PATH 환경변수는 파일을 검색하는데 사용됨
exec() call example
User process tree
shell의 parent는 init
a.out의 parent는 shell
Shell & process tree
$ : shell, the process of this user
$ ./a.out : shell and a.out : processes of this user
$ cat myfile : shell and cat : processes of this user
$ ./a.out & : a.out as a background process
$ rm myfile : shell, a.out and rm are running processes
$ ./a.out > output : stdout is changed to “output” before exec().
This is called “I/O redirection”.
Simple shell example
shell과 유사하게 동작하는 자신만의 프로그램 만들기
유저로부터 command 받아서 fork 시킨 다음
입력받은 프로그램을 실행시키도록 만들기
Multitask scheduling
Context switching (or process switching)
• 타이머 인터럽트로 정기적으로 발생
• OS는 현재 CPU의 context를 PCB에 저장해야함 (why?)
문제
• 프로그램에서 어떤 문장이 중단될지 미리 알 수 없습니다. (즉, 선점)
• 일부 프로그램은 일관성 없는 출력을 초래할 수 있습니다(레이스 조건(race condition)이라고 함).
예 (이 프로그램에서 어떤 일이 일어날지 생각해 보세요)
File sharing b/w P&C
Inter-Process Communication (IPC)
가능한 통신 방법
• 파일을 공유
• 열린 파일의 파일 포인터를 상위 파일과 하위 파일 간에 공유
• 메시지 큐
• semaphores(explained later)
• 신호(SP 참조)
• 네트워크 소켓
• pipe : circular queue bet. processes
– named pipe : 시스템 내의 임의의 프로세스 간
– unnamed pipe : 부모와 자식 사이
Pipe
Pipe
• 프로세스 간의 IPC 도구
• block & wakeup으로 race condition를 피함
• 2개의 r/w 포인터로 작성된 FIFO 파일
– 하나는 읽기 전용
– 다른 하나는 쓰기 전용
• 시스템은 가변 크기 queue entry 와 상호 제외를 갖춘 ring-buffer 를 제공한다.
링버퍼 -> 덮어쓰는 형식(데이터 가져가면 비워짐)
• 빈 파이프에 대한 읽기 시도가 차단(blocking)의 원인이 됨
• 블로킹 판독은 파이프에 쓰기가 발생하거나 파이프가 닫혔을 때 반환됨
Pipe example