System Call - fork(), wait(), exec()

zeo·2021년 10월 5일
1

1. fork() : 프로세스 생성 위한 system call

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main(int argc, char *argv[]) {
    printf("hello world (pid:%d)\n", (int) getpid());
    // PID는 프로세스의 실행이나 중단과 같이 특정 프로세스를 대상으로 작업 해야 할 경우, 프로세스를 지칭하기 위해 사용
 
    int rc = fork();
    // fork() 시스템 콜 호출(프로세스 생성 위해)
    // fork()로부터 부모 프로세스는 생성된 자식 프로세스의 PID를 반환받고, 
    // 자식 프로세스는 0을 반환받음

    if (rc < 0) { // 실패
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) { // 자식 프로세스 생성
    // 자식 프로세스는 자신의 주소 공간, register, pc 값을 가짐!
        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;
}

2. wait() : 부모 프로세스가 자식 프로세스의 종료를 대기해야 하는 경우 사용

#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) {
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) { // 자식 프로세스 생성
        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;
}
  • 부모 프로세스는 wait() 시스템 콜을 호출하여 자식 프로세스가 종료될 때까지 자신의 실행을 잠시 중단하고, 자식 프로세스가 종료되면 wait()는 리턴함

  • wait() 에서는 항상 자식 프로세스가 먼저 출력을 수행함
    -> 자식 프로세스가 부모 프로세스보다 먼저 실행되면 자식 프로세스가 먼저 출력됨
    -> 부모 프로세스가 자식 프로세스보다 먼저 실행되면 곧바로 wait() 호출
    -> wait() 시스템 콜은 자식 프로세스가 종료될 때까지 리턴하지 않음
    -> 부모 프로세스가 먼저 실행되더라도, 자식 프로세스가 종료된 후 wait()가 리턴하고, 그런 다음 부모 프로세스가 출력함

3. exec() : 자기 자신이 아닌 다른 프로그램을 실행해야 할 때 사용

! fork() 시스템 콜은 자신의 복사본을 생성하여 실행하는 반면, exec() 시스템 콜은 자신의 복사본이 아닌 다른 프로그램을 실행해야 할 경우에 사용

int
main(int argc, char *argv[]) {
    printf("hello world (pid:%d)\n", (int) getpid());
    int rc = fork();
    if (rc < 0) {
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) { // 자식 프로세스 생성
        printf("hello, i am child (pid:%d)\n", (int) getpid());
        char *myargs[3];
        myargs[0] = strdup("wc"); // 프로그램 : "wc"(words count)
        myargs[1] = strdup("p3.c"); // 인자 : 단어 셀 파일
        myargs[2] = NULL; // 배열의 끝 표시
        execvp(myargs[0], myargs); // "wc" 실행하기 위해 execvp() 시스템 콜 호출
    } else { // 부모 프로세스는 해당 경로를 따라 실행
        int wc = wait(NULL);
        printf("hello, i am parent of %d (wc:%d) (pid:%d)\n", rc, wc, (int)getpid());
    }
    return 0;
}
  • 실행 파일 이름과 인자가 주어지면, 해당 실행 파일의 코드와 정적 데이터를 읽어 들여 현재 실행 중인 프로세스의 세그먼트와 정적 데이터 부분을 덮어쓴다
  • 힙과 스택 및 프로그램의 다른 주소 공간들로 새로운 프로그램을 실행할 수 있도록 다시 초기화함
  • 그런 다음 os는 프로세스의 argv와 같은 인자를 전달하여 프로그램 실행 시킴
  • 새로운 프로세스는 생성하지 않으며, 현재 실행 중인 프로그램을 다른 실행 중인 프로그램으로 대체하는 것

0개의 댓글