Linux 프로세스프로그래밍 Programming - 프로세스생성 : fork, exec - 프로세스동기화 : wait - 프로세스관리함수 프로세스관련함수 프로세스생성과종료 함수 의미 fork 자신과완전히동일한프로세스를생성한다. exec 계열지정한실행파일로부터프로세스를생성한다. exit 종료에따른상태값을부모프로세스에게전달하며프로세스를종료한다. atexit exit 로프로세스를종료할때수행할함수를등록한다. _exit atexit 로등록한함수를호출하지않고프로세스를종료한다. wait 자신의자식프로세스가종료할때까지대기상태가된다. waitpid 지정한자신의자식프로세스가종료할때까지대기상태가된다. 2
프로세스관련함수 프로세스속성과환경변수 함수 의미 getpid, getppid 자신 ( 또는부모 ) 의프로세스식별번호를구한다. 자신의프로세스그룹식별번호를구하거나변경한다. getpgrp, setpgrp getpgid, setpgid 지정한프로세스의그룹식별번호를구하거나변경한다. getsid 지정한프로세스의세션식별번호를구한다. setsid 현재프로세스가새로운세션을생성한다. getenv, putenv 환경변수의값을구하거나, 새로운환경변수를등록 / 변경한다. setenv 새로운환경변수를등록하거나변경한다. unsetenv 등록된환경변수를삭제한다. 3 fork 프로세스를복제하여완전히동일한자식프로세스생성 #include <sys/types.h> #include <unistd.h> pid_t fork(void); 반환값 fork 호출이성공하여자식프로세스가만들어지면부모프로세스에서는자식프로세스의프로세스 ID 가반환되고자식프로세스에서는 0 을반환한다. fork 호출이실패하여자식프로세스가만들어지지않으면부모프로세스에서는 -1 이반환된다. 4
fork fork 로프로세스생성하면 생성하는쪽이부모 (parent), 생성된프로세스는자식 (child) 서로다른프로세스이다 서로다른 PID 자식의 PPID 는부모프로세스의 PID 실행상태는똑같다. fork 를호출하던시점의 context( 실행상태 ) 를그대로물려받는다. 프로그램코드 변수, 레지스터값 스택의값등등 fork 이후부터는각자자기길을간다! 5 fork fork 로프로세스생성하면 6
fork 사용예 pid_t pid; pid = fork(); if (pid > 0) // 부모프로세스가수행할부분 else (pid == 0) // 자식프로세스가수행할부분 else // fork 호출이실패할경우... 부모와자식이수행할일이다르다면 pid 반환값을이용해구분하여코딩한다. 7 exec 계열 경로또는파일이름으로지정한실행파일을실행하여프로세스생성 #include <unistd.h> extern char **environ; int execl (const char *path, const char *arg,...); int execlp (const char *file, const char *arg,...); int execv (const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); path file arg argv 반환값 실행파일의경로로상대경로와절대경로모두사용가능경로이름이아닌실행파일의이름실행파일과전달인자리스트. 마지막인자는반드시 NULL arg와같으나문자열포인터배열형태. 배열의마지막요소는반드시 NULL 문자열. 호출이성공하면호출프로세스는종료되고반환값을받을수없다. 실패시 -1 반환. 8
exec 계열 사용예 execlp( ls, ls, -l, subdir, NULL); == $ ls l subdir 실행파일이름 명령어와옵션, 전달인자 exec 호출결과 caller callee 관계생성 caller 는종료된다. whereis, which 활용 caller 의메모리영역을 callee 가차지하고 PID 도물려받는다. 이름구분 l 은리스트형태인자, v 는문자포인터배열형태인자 p 가없으면경로를직접지정, p 가있으면환경변수 PATH 이용 9 exec 계열 exec 로프로세스생성하면 10
fork & exec fork, exec 비교 fork exec 계열 계열 프로세스의원본부모프로세스를복제지정한프로그램 ( 파일 ) 을실행명령행인자부모프로세스것을그대로사용필요할경우새로적용부모 ( 또는호출 ) 자식프로세스를생성한후에호출이성공할경우호출 (Caller) 프로세스의상태도자신의나머지코드를실행프로세스종료자식 ( 또는피호출 ) 프로세스의메모리부모프로세스와다른곳에위호출프로세스가있던자리를피호상의위치치. 처음내용은같다. 출프로세스가물려받는다. 자식 ( 또는피호출 ) 프로세스의실행시작점 fork 호출이후부터수행 프로그램의처음부터수행 프로세스식별번호자식에게새로운 PID Caller와 Callee PID 동일프로세스의원본인파일에대한권한권한도복제실행파일에대한실행권한이필요 11 fork & exec fork 와 exec 함께사용 부모와자식이다른작업을하면서둘다살아있게하려면? fork 로일단복제 자식프로세스에서 exec 를호출하여다른프로그램실행 pid_t pid; pid = fork(); if (pid > 0) { // 부모프로세스가수행할부분 } else (pid == 0) // 자식프로세스 execl(,, ); else... // fork 호출이실패할경우 12
exit 프로세스를종료하고부모프로세스에게종료상태값전달 #include <stdlib.h> void exit (int status); status 반환값 부모프로세스에게전달되는상태값으로 0~255(1바이트 ) 의값이사용된다. 없음 프로세스를명시적으로종료시킴 암묵적종료 : 더이상수행할문장이없거나 return 문수행 status 값에는정해진의미가없다! 보통 0 이정상종료 13 atexit exit 호출시종료전에수행할함수들을등록 #include <stdlib.h> int atexit (void (*function)(void)); function 반환값 atexit로등록할함수의이름호출이성공하면 0을반환, 실패하면 0이아닌값을반환 함수는 void function(void); 형으로정의되어야한다. 종료시마무리작업 (clean-up-action) 깔끔한마무리를위해수행해야하는작업들 파일닫기 자식프로세스종료등 최대 32 개까지등록가능하며등록역순으로실행된다 14
_exit exit 와같지만마무리작업이없다. clean-up-action 에해당하는작업을등록해두었더라도수행하지않는다. #include <unistd.h> void _exit (int status); status 반환값 부모프로세스에게전달되는상태값으로 0~255(1바이트 ) 의값이사용된다. 없음 15 예제 1 실행결과 : 16
실행결과 : 예제 2 절대로 linda 에서테스트하지말것!!! 17 wait 자식프로세스가종료할때까지대기 #include <sys/types.h> #include <sys/wait.h> pid_t wait (int *status); status 반환값 자식프로세스가 exit 함수로종료하면서전달하는종료상태값으로 0에서 255 사이의값을가진다. 호출이성공했을경우종료한자식프로세스의식별번호가반환되고, 실패할경우 -1이반환된다. 이미종료한상태라면대기하지않고처리 status: 전달된결과는부모의두번째바이트에저장 18
wait 특별한상태의프로세스 좀비프로세스 (Zombie process) == defunct process CPU, memory 등의자원을사용하지는않으나커널의작업리스트에는존재하는프로세스 부모가 wait 하고정상종료하면죽을수있다. 고아프로세스 (Orphan process) 하나이상의자식프로세스가수행중인상태에서부모가먼저종료 문제가되나? 지나치게많을경우시스템자원고갈 init process (PID 1) 가거두어처리해준다. 19 waitpid PID 로지정한자식프로세스의종료대기 #include <sys/types.h> #include <sys/wait.h> pid_t waitpid(pid_t pid, int *status, int options); pid status 자식프로세스의식별번호자식프로세스가 exit 로종료하면서전달하는종료상태값 options 부모프로세스의대기방법을선택. 일반적으로 0이사용된다. 반환값호출이성공했을때종료한자식프로세스가있다면자식프로세스의식별번호가반환, WNOHANG 옵션을사용할때종료한자식프로세스가없으면 0을반환. 호출이실패할경우 -1을반환. wait 는가장먼저종료되는자식프로세스처리 waitpid: 부모가처리순서를결정할수있다. -1 이면 wait 와같다. 옵션에따라서자식종료시까지대기안할수도있다. 20
waitpid 옵션 WNOHANG PID 로지정한자식프로세스가종료하지않았으면자신의일을계속수행 pid_t pid1; if ((pid = fork()) > 0) { while (!waitpid(pid, &status, WNOHANG)) { printf( parent: %d\n, status++ ); sleep(1); } } else if ( pid == 0) { sleep (5); printf( bye!\n ); exit(0); } 21 예제 3 실행결과 : 22
getpid, getppid 자신또는부모의식별번호를구한다. #include <sys/types.h> #include <unistd.h> pid_t getpid (void); pid_t getppid (void); 반환값프로세스의식별번호 PID: 프로세스식별번호 음이아닌정수 한시점에서프로세스를식별하는유일한번호 23 프로세스그룹 프로세스그룹의식별번호를구하거나변경 #include <sys/types.h> #include <unistd.h> int setpgid (pid_t pid, pid_t pgid); pid_t getpgid (pid_t pid); int setpgrp (void); pid_t getpgrp void); pid pgid 반환값 프로세스식별번호프로세스그룹의식별번호 setpgid와 setpgrp는호출이성공할경우 0을반환, 실패할경우 -1을반환 getpgid는호출이성공할경우프로세스의그룹식별번호를반환, 실패할경우 -1을반환 getpgrp은항상프로세스의그룹식별번호를반환 24
프로세스그룹 프로세스그룹 여러프로세스들이하나의그룹에속할수있음 시그널처리를동시에할수있다. 그룹식별번호를별도로가진다 그룹리더의 PID cat grep printf more 함수와파라미터의의미 setpgid (pid, pgid) pid 프로세스의그룹 ID 를 pgid 로변경 pid = 0: 현재프로세스에적용 pgid = 0: pid 를 pgid 로사용 setpgrp, getpgrp setpgrp == setpgid(0,0): 현재프로세스를리더로하는그룹설정 getpgrp == getpgid(0): 현재프로세스의그룹 ID 구하기 25 세션식별번호 세션 (Session) 로그온중인하나의단말을포함하는단위 세션 그룹 프로세스 세션리더의경우 : PID == PGID == PSID #include <sys/types.h> #include <unistd.h> pid_t getsid (pid_t pid); pid_t setsid (void); pid 반환값 프로세스의식별번호. 0이면현재프로세스성공하면프로세스의세션식별번호를반환, 실패하면 -1을반환 setsid 리더가아닌경우새로운세션생성 ( 일반적으로셸이리더 ) 호출한프로세스가세션과그룹의리더가된다. 26
세션식별번호 종료와세션 로그인셸이세션리더 셸을종료하면다른프로세스도종료 27 세션식별번호 데몬 (daemon) 셸종료후에도살아있는프로세스 init 프로세스의자식 특정터미널에연결되지않아야한다. 주로서버 ( 서비스제공자 ) 로동작 setsid 로만들수있다. 서버데몬만들기 fork() 로자식을만들고부모는종료 (exit) 한다. setsid() 로새세션을만든다. chdir() 로작업디렉터리를 / 로바꾼다. 입출력을재지정한다. 열린모든파일을닫고, 표준입출력을 /dev/null 로지정 C 표준함수 daemon(0, 0) 으로호출하는것과같은효과 28
세션식별번호 데몬예제 29 환경변수 환경변수의값을알아오거나새로설정 #include <stdlib.h> char *getenv (const char *name); int setenv (const char *name, const char *value, int overwrite); int putenv (char *string); void unsetenv (const char *name); name value string 환경변수의이름에해당하는문자열환경변수의값에해당하는문자열 name=value 형식으로구성된문자열 overwrite name 환경변수가이미존재할경우덮어쓰기여부를결정한다. 0이면덮어쓰기를하고 0이아니면덮어쓰기를하지않는다. 반환값 getenv는성공할경우 name에해당하는환경변수의값에대한문자열포인터를반환, 실패할경우 NULL을반환 putenv와 setenv는성공할경우 0을반환, 실패할경우 -1을반환 30
환경변수 프로세스간에값주고받기 exec 계열함수로프로세스생성시환경변수값전달 setenv/getenv envlist 추가하여 exec 함수호출 setenv getenv putenv( APPLE=RED ); execl( prog, prog, NULL); caller if (getenv( APPLE ) { printf( %s\n, getenv( APPLE )); unsetenv( APPLE ); } callee (prog) 31 환경변수 프로세스간에값주고받기 envlist 추가하여 exec 함수호출 exec 계열의함수 execle, execve 사용 caller char *envlist[] = {"APPLE=BANANA", NULL};... execle( prog", prog", NULL, envlist); execve( prog", arglist, envlist); callee (prog) extern char *envlist[]; int main (void) { 또는 int main (int argc, char *argv[], char *envlist[]) { while (*envlist) { } } while (*envlist) { } } 32
예제 4 실행결과 : 33