학습목표 프로세스를생성하는방법을이해한다. 프로세스를종료하는방법을이해한다. exec함수군으로새로운프로그램을실행하는방법을이해한다. 프로세스를동기화하는방법을이해한다. 프로세스생성과실행 IT CookBook, 유닉스시스템프로그래밍 2/24 목차 프로세스생성 프로세스종료함수 exec 함수군활용 exec 함수군과 fork 함수 프로세스동기화 프로세스생성 [1] 프로그램실행 : system(3) #include <stdlib.h> int system(const char *string); 새로운프로그램을실행하는가장간단한방법이나비효율적이므로남용하지말것 실행할프로그램명을인자로지정 [ 예제 6-1] system 함수사용하기 ex6_1.c 01 #include <stdlib.h> 02 #include <stdio.h> 03 04 int main(void) { 05 int a; 06 a = system("ps ef grep han > han.txt"); 07 printf("return Value : %d\n", a); 09 return 0; 10 } # ex6_1.out Return Value : 0 3/24 # cat han.txt root 736 735 0 10:31:02 pts/3 root 735 734 0 10:31:02 pts/3 0:00 grep han 0:00 sh c ps ef grep han> han.txt 4/24
프로세스생성 [2] [ 예제 6-2] fork 함수사용하기 ex6_2.c 프로세스생성 : fork(2) #include <sys/types.h> #include <unistd.h> pid_t fork(void); 새로운프로세스를생성 : 자식프로세스 fork 함수를호출한프로세스 : 부모프로세스 자식프로세스는부모프로세스의메모리를복사 RUID, EUID, RGID, EGID, 환경변수 열린파일기술자, 시그널처리, setuid, setgid 현재작업디렉토리, umask, 사용가능자원제한 부모프로세스와다른점 자식프로세스는유일한 PID 를갖는다 자식프로세스는유일한 PPID 를갖는다. 부모프로세스가설정한프로세스잠금, 파일잠금, 기타메모리잠금은상속안함 자식프로세스의 tms 구조체값은 0 으로설정 부모프로세스와자식프로세스는열린파일을공유하므로읽거나쓸때주의해야한다. 5/24 06 int main(void) { 07 pid_t pid; 09 switch (pid = fork()) { 10 case 1 : /* fork failed */ 11 perror("fork"); 12 exit(1); 13 break; 14 case 0 : /* child process */ 15 printf("child Process My PID:%d, My Parent's PID:%d\n", 16 (int)getpid(), (int)getppid()); 17 break; 18 default : /* parent process */ 19 printf("parent process My PID:%d, My Parent's PID:%d, " "My Child's PID:%d\n", (int)getpid(), (int)getppid(), (int)pid); 21 break; 22 } # ex6_2.out 23 24 printf("end of fork of fork\n"); fork 함수의리턴값 0 은자식프로세스가실행 Child Process My PID:796, My Parent's PID:795 26 return Parent 0; process My PID:795, My Parent's PID:695, My Child's PID:796 27 } End of fork 6/24 프로세스종료함수 [1] 프로그램종료 : exit(2) #include <stdlib.h> void exit(int status); status : 종료상태값 프로그램종료시수행할작업예약 : atexit(2) #include <stdlib.h> int atexit(void (*func)(void)); func : 종료시수행할작업을지정한함수명 프로세스종료함수 [2] 프로그램종료함수의일반적종료절차 1. 모든파일기술자를닫는다. 2. 부모프로세스에종료상태를알린다. 3. 자식프로세스들에 SIGHUP 시그널을보낸다. 4. 부모프로세스에 SIGCHLD 시그널을보낸다. 5. 프로세스간통신에사용한자원을반납한다. 프로그램종료 : _exit(2) #include <unistd.h> void _exit(int status); 일반적으로프로그램에서직접사용하지않고 exit 함수내부적으로호출 7/24 8/24
[ 예제 6-3] exit, atexit 함수사용하기 ex6_3.c exec 함수군활용 01 #include <stdlib.h> 02 #include <stdio.h> 03 04 void cleanup1(void) { 05 printf("cleanup 1 is called.\n"); 06 } 07 void cleanup2(void) { 09 printf("cleanup 2 is called.\n"); 10 } 11 12 int main(void) { 13 atexit(cleanup1); 14 atexit(cleanup2); 15 16 exit(0); 17 } 종료시수행할함수지정지정한순서의역순으로실행 ( 실행결과확인 ) # ex6_3.out Cleanup 2 is called. Cleanup 1 is called. 9/24 exec 함수군 exec 로시작하는함수들로, 명령이나실행파일을실행할수있다. exec 함수가실행되면프로세스의메모리이미지는실행파일로바뀐다. exec 함수군의형태 6 가지 #include <unistd.h> int execl(const char *path, const char *arg0,, const char *argn, (char *)0); int execv(const char *path, char *const argv[]); int execle(const char *path, const char *arg0,, const char *argn, (char *)0, char *const envp[]); int execve(const char *path, char *const argv[], char *const envp[]); int execlp(const char *file, const char *arg0,, const char *argn, (char *)0); int execvp(const char *file, char *const argv[]); path : 명령의경로지정 file : 실행파일명지정 arg#, argv : main 함수에전달할인자지정 envp : main 함수에전달할환경변수지정 함수의형태에따라 NULL 값지정에주의해야한다. 10/24 [ 예제 6-4] execlp 함수사용하기 ex6_4.c [ 예제 6-5] execv 함수사용하기 ex6_5.c 01 #include <unistd.h> 02 #include <stdlib.h> 03 #include <stdio.h> 04 05 int main(void) { 06 printf(" > Before exec function\n"); 07 if (execlp("ls", "ls", " a", (char *)NULL) == 1) { 09 perror("execlp"); 10 exit(1); 11 } 12 13 printf(" > After exec function\n"); 14 15 return 0; 16 } # ex6_4.out 첫인자는관례적으로실행파일명지정 인자의끝을표시하는 NULL 포인터 메모리이미지가 ls 명령으로바뀌어 13 행은실행안됨 > Before exec function. ex6_1.c ex6_3.c ex6_4.out.. ex6_2.c ex6_4.c han.txt 01 #include <unistd.h> 02 #include <stdlib.h> 03 #include <stdio.h> 04 05 int main(void) { 06 char *argv[3]; 07 printf("before exec function\n"); 09 10 argv[0] = "ls"; 11 argv[1] = " a"; 12 argv[2] = NULL; 13 if (execv("/usr/bin/ls", argv) == 1) { 14 perror("execv"); 15 exit(1); 16 } 17 18 printf("after exec function\n"); 19 20 return 0; 21 } 첫인자는관례적으로실행파일명지정 인자의끝을표시하는 NULL 포인터 경로로명령지정 역시실행안됨 # ex6_5.out > Before exec function. ex6_1.c ex6_3.c ex6_5.c han.txt.. ex6_2.c ex6_4.c ex6_5.out 11/24 12/24
[ 예제 6-6] execve 함수사용하기 ex6_6.c [ 예제 6-6] (2) ex6_6_arg.c 파일 ex6_6_arg.c 05 int main(void) { 06 char *argv[3]; 07 char *envp[2]; 09 printf("before exec function\n"); 10 11 argv[0] = "arg.out"; 실행파일명지정 12 argv[1] = "100"; 13 argv[2] = NULL; 인자의끝을표시하는 NULL 포인터 14 15 envp[0] = "MYENV=hanbit"; 환경변수설정 16 envp[1] = NULL; 17 ex6_6_arg.c를컴파일하여생성 18 if (execve("./arg.out", argv, envp) == 1) { 19 perror("execve"); 20 exit(1); 21 } 22 23 printf("after exec function\n"); 24 25 return 0; 26 } # ex6_6.out > Before exec function > In ex6_6_arg.c Main argc = 2 argv[0] = arg.out argv[1] = 100 MYENV=hanbit 13/24 01 #include <stdio.h> 02 03 int main(int argc, char **argv, char **envp) { 04 int n; 05 char **env; 06 07 printf("\n > In ex6_6_arg.c Main\n"); printf("argc = %d\n", argc); 09 for (n = 0; n < argc; n++) 10 printf("argv[%d] = %s\n", n, argv[n]); 11 12 env = envp; 13 while (*env) { 14 printf("%s\n", *env); 환경변수출력 15 env++; 16 } 17 18 return 0; 19 } 인자값출력 14/24 exec 함수군과 fork 함수 [ 예제 6-7] fork 와 exec 함수사용하기 ex6_7.c fork 로생성한자식프로세스에서 exec 함수군을호출 자식프로세스의메모리이미지가부모프로세스이미지에서 exec 함수로호출한새로운명령으로대체 자식프로세스는부모프로세스와다른프로그램실행가능 부모프로세스와자식프로세스가각기다른작업을수행해야할때 fork 와 exec 함수를함께사용 15/24 06 int main(void) { 07 pid_t pid; 09 switch (pid = fork()) { 10 case 1 : /* fork failed */ 11 perror("fork"); 12 exit(1); 13 break; 14 case 0 : /* child process */ 자식프로세스에서 execlp 함수실행 15 printf(" > Child Process\n"); 16 if (execlp("ls", "ls", " a", (char *)NULL) == 1) { 17 perror("execlp"); 18 exit(1); 19 } 20 exit(0); 21 break; 22 default : /* parent process */ 부모프로세스는이부분실행 23 printf(" > Parent process My PID:%d\n,(int)getpid()); 24 break; # ex6_7.out 25 } > Child Process 27 return 0; ex6_1.c ex6_3.c ex6_5.c ex6_6_arg.c ex6_7.out 28 } ex6_2.c ex6_4.c ex6_6.c ex6_7.c han.txt > Parent process My PID:10535 16/24
프로세스동기화 부모프로세스와자식프로세스의종료절차 부모프로세스와자식프로세스는순서와상관없이실행하고먼저실행을마친프로세스는종료 부모프로세스와자식프로세스사이에종료절차가제대로진행되지않으면좀비프로세스발생 좀비프로세스 실행을종료하고자원을반납한자식프로세스의종료상태를부모프로세스가가져가지않으면좀비프로세스발생 좀비프로세스는프로세스테이블에만존재 좀비프로세스는일반적인제거방법은없음 좀비프로세스를방지하기위해부모프로세스와자식프로세스를동기화해야함 프로세스동기화함수 [1] 프로세스동기화 : wait(3) #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *stat_loc); stat_loc : 상태정보를저장할주소 wait 함수는자식프로세스가종료할때까지부모프로세스를기다리게함 부모프로세스가 wait 함수를호출하기전에자식프로세스가종료하면 wait 함수는즉시리턴 wait 함수의리턴값은자식프로세스의 PID 리턴값이 -1 이면살아있는자식프로세스가하나도없다는의미 고아프로세스 자식프로세스보다부모프로세스가먼저종료할경우자식프로세스들은고아프로세스가됨 고아프로세스는 1 번프로세스 (init) 의자식프로세스로등록 17/24 18/24 [ 예제 6-8] wait 함수사용하기 ex6_8.c 프로세스동기화함수 [2] 07 int main(void) { int status; 09 pid_t pid; 11 switch (pid = fork()) { 12 case 1 : /* fork failed */ 13 perror("fork"); 14 exit(1); 15 break; 16 case 0 : /* child process */ 17 printf(" > Child Process\n"); 18 exit(2); 19 break; 20 default : /* parent process */ 21 while (wait(&status)!= pid) 22 continue; 23 printf(" > Parent process\n"); 24 printf("status: %d, %x\n", status, status); 25 printf("child process Exit Status:%d\n,status >> 8); 26 break; 27 } 29 return 0; 30 } # ex6_8.out > Child Process > Parent process Status: 512, 200 Child process Exit Status:2 자식프로세스의종료를기다림 오른쪽으로 8 비트이동해야종료상태값을알수있음 19/24 특정자식프로세스와동기화 : waitpid(3) #include <sys/types.h> #include <sys/wait.h> pid_t waitpid(pid_t pid, int *stat_loc, int options); pid 에지정할수있는값 -1 보다작은경우 : pid 의절댓값과같은프로세스그룹 ID 에속한자식프로세스중임의의프로세스의상태값요청 -1 인경우 : wait 함수처럼임의의자식프로세스의상태값을요청 0 인경우 : 함수를호출한프로세스와같은프로세스그룹에속한임의의프로세스의상태값요청 0 보다큰경우 : 지정한 PID 의상태값요청 options: waitpid 함수의리턴조건 WCONTINUED: 수행중인자식프로세스의상태값리턴 WNOHANG: pid 로지정한자식프로세스의상태값을즉시리턴받을수없어도이를호출한프로세스의실행을블록하지않고다른작업을수행토록함 WNOWAIT: 상태값을리턴한프로세스가대기상태에머물수있도록함 WUNTRACED: 실행을중단한자식프로세스의상태값을리턴 20/24
[ 예제 6-9] waitpid 함수사용하기 ex6_9.c 07 int main(void) { int status; 09 pid_t pid; 10 11 if ((pid = fork()) < 0) { /* fork failed */ 12 perror("fork"); 13 exit(1); 14 } 15 16 if (pid == 0) { /* child process */ 17 printf(" > Child process\n"); 18 sleep(3); 19 exit(3); 20 } 21 22 printf(" > Parent process\n"); 23 24 while (waitpid(pid, &status, WNOHANG) == 0) { 25 printf("parent still wait\n"); 26 sleep(1); 27 } 28 29 printf("child Exit Status : %d\n", status>>8); 30 31 return 0; 32 } # ex6_9.out > Child process > Parent process Parent still wait Parent still wait Parent still wait Child Exit Status : 3 WNOHANG 이므로 waitpid 함수는블록되지않고 25~26 행반복실행 21/24 IT CookBook, 유닉스시스템프로그래밍