fork() System Call
- 새로운 프로세스를 생성한다.
- 새로 생성된 프로세스는 함수를 호출한 프로세스의address space, registers, PC를 복사한다.
- fork() 함수는 프로세스 id, 즉 pid를 return하게 되는데 부모 프로세스에서는 자식의 pid, 자식 프로세스에서는 0, 함수 실행 실패시 -1을 반환하게 된다.
//p1.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[]){
printf("hello world (pid : %d)\n", (int) getpid());
int rc = fork();
if (rc < 0){ // fork 실패; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if(rc==0){ // child(새로운(자식) 프로세스)
printf("hello, I am child (pid : %d)\n", (int) getpid());
} else{ //부모 프로세스
printf("hello, I am parent of %d (pid : %d)\n", rc, (int)getpid());
}
return 0;
}
- 해당 결과는 다음과 같은데 부모가 먼저 나올지 자식이 먼저 나올지는 결정되지 않는다.
//결과1.
>> ./p1
hello world (pid: 29146)
hello, I am child (pid : 29147)
hello, I am parent of 29147 (pid : 29146)
//결과2.
>> ./p1
hello world (pid: 29146)
hello, I am parent of 29147 (pid : 29146)
hello, I am child (pid : 29147)
wait() System Call
- 이 system call은 자식이 수행되고 종료될때까지 부모는 종료되지 않는다.
- wait() 함수는 자식 프로세스의 pid값을 return 받는다. 만일 자식 프로세스가 없다면 -1값(에러값)을 반환받는다.
//p2.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char* argv[]){
printf("hello world (pid : %d)\n", (int) getpid());
int rc = fork();
if (rc < 0){ // fork 실패; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if(rc==0){ // child(새로운(자식) 프로세스)
printf("hello, I am child (pid : %d)\n", (int) getpid());
} else{ //부모 프로세스
int wc = wait(NULL);
printf("hello, I am parent of %d (wc:%d) (pid : %d)\n", rc,wc, (int)getpid());
}
return 0;
}
- 해당 결과는 다음과 같으며 이 결과값은 자식 프로세스가 먼저 시행되고 부모 프로세스가 시행되는 순서로 나온다.
//결과
>> ./p2
hello world (pid: 29266)
hello, I am child (pid : 29267) //순서 결정(자식 먼저)
hello, I am parent of 29267 (wc:29267) (pid : 29266)
exec() System Call
- 현재 calling하는 프로그램과 다른 프로그램을 실행시킨다.
- exec() system call은 execl, execv, execlp, execvp 등의 함수군을 가지고 있다.
//p3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char* argv[]){
printf("hello world (pid : %d)\n", (int) getpid());
int rc = fork();
if (rc < 0){ // fork 실패; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if(rc==0){ // child(새로운(자식) 프로세스)
printf("hello, I am child (pid : %d)\n", (int) getpid());
char *myargs[3];
myargs[0] = strdup("wc"); // strdup는 "wc"의 주소를 반환해줌
myargs[1] = strdup("p3.c");
myargs[2] = NULL;
execvp(myargs[0], myargs); // 파일명은 "wc"(myargs[0])이고 명령어는 ./wc p3.c (해당 p3.c의 행count, 단어count, 문자수count, 파일명을 출력한는 프로그램 wc 실행)
printf("this shouldn't print out"); // execvp 함수에 의해 이 줄은 출력되지 않을 것이다.
} else{ //부모 프로세스
int wc = wait(NULL);
printf("hello, I am parent of %d (wc:%d) (pid : %d)\n", rc,wc, (int)getpid());
}
return 0;
}
//결과
>> ./p3
hello world (pid: 29383)
hello, I am child (pid : 29384) //순서 결정(자식 먼저)
29 107 1030 p3.c // 행 단어 문자수 파일명 출력
hello, I am parent of 29384 (wc:29384) (pid : 29383)
위에 이용한것 다 합친 후 redirection
- fork와 exec 사이에 부가적인 일 시키기
//p4.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
int main(int argc, char* argv[]){
int rc = fork();
if (rc < 0){ // fork 실패; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if(rc==0){ // child(새로운(자식) 프로세스: 출력되던 standard output을 file로 저장)
close(STDOUT_FILENO);
open("./p4.output", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
char *myargs[3];
myargs[0] = strdup("wc"); // strdup는 "wc"의 주소를 반환해줌
myargs[1] = strdup("p4.c");
myargs[2] = NULL;
execvp(myargs[0], myargs); // 파일명은 "wc"(myargs[0])이고 명령어는 ./wc p3.c (해당 p4.c의 행count, 단어count, 문자수count, 파일명을 출력한는 프로그램 wc 실행)
} else{ //부모 프로세스
int wc = wait(NULL);
}
return 0;
}
//결과
>> ./p4
>> cat p4.output (cat: 파일 내용을 볼 수 있다.)
32 109 846 p4.c