본문 바로가기

Computer Science/Operating System

[Operating System] 5. System Call

728x90
반응형
SMALL

0. System Call

fork(), exec(), wait()은 Process 생성과 제어를 위한 System Call이다. 

  • fork, exec는 새로운 Process 생성과 관련이 있다.
  • wait은 Process(Parent)가 만든 다른 Process(Child)가 끝날 때까지 기다리는 명령이다.

 

1. Fork

Fork는 새로운 Process를 생성할 때 사용한다. 

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

int main(int argc, char *argv[]) {
    printf("pid : %d", (int) getpid()); // pid : 29146
    
    int rc = fork();					// 주목
    
    if (rc < 0) {
        exit(1);
    }									// (1) fork 실패
    else if (rc == 0) {					// (2) child 인 경우 (fork 값이 0)
        printf("child (pid : %d)", (int) getpid());
    }
    else {								// (3) parent case
        printf("parent of %d (pid : %d)", rc, (int)getpid());
    }
}
pid : 29146

parent of 29147 (pid : 29146)

child (pid : 29147)

코드를 수행하면 위와 같이 출력된다. child의 pid는 parent보다 1 크다. parent와 child의 순서는 스케줄러에 의해 결정된다.

 

PID란 프로세스 식별자이다. UNIX 시스템에서 PID는 프로세스에게 명령을 할 때 사용한다. Fork가 실행되는 순간 프로세스(child)가 하나 더 생기는데 이때 생긴 프로세스는 fork를 만든 프로세스(parent)와 동일한 복사본을 갖게 된다. 이때 OS는 똑같은 2개의 프로그램이 동작한다고 생각하고 fork가 reaturn 될 차례라고 생각한다. 이로 인해 새로 생성된 프로세스(child)는 main에서 시작하지 않고 if문부터 시작하게 된다.

 

단 parent와 child의 fork 값이 다르다. parent의 fork값은 child의 pid값이며, child의 fork값은 0이다.

 

 

2. Wait

Wait은 child 프로세스가 종료될 때까지 기다리는 작업이다. 위 코드에서 int wc = wait(NULL)이 추가된다.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {
    printf("pid : %d", (int) getpid()); // pid : 29146
    
    int rc = fork();					// 주목
    
    if (rc < 0) {
        exit(1);
    }									// (1) fork 실패
    else if (rc == 0) {					// (2) child 인 경우 (fork 값이 0)
        printf("child (pid : %d)", (int) getpid());
    }
    else {								// (3) parent case
        int wc = wait(NULL)				// 추가된 부분
        printf("parent of %d (wc : %d / pid : %d)", wc, rc, (int)getpid());
    }
}
pid : 29146

child (pid : 29147)

parent of 29147 (wc : 29147 / pid : 29146)

wait을 통해 child의 실행이 끝날 때까지 기다린다. parent가 먼저 실행되더라도 wait은 child가 끝나지 전에는 return하지 않으므로 반드시 child가 먼저 실행되고 종료된다.

 

 

3. exec

fork는 동일한 프로세스의 내용을 여러 번 동작할 때 사용한다. 만약 child와 parent가 다른 동작을 하고 싶다면 exec을 사용하면 된다.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {
    printf("pid : %d", (int) getpid()); // pid : 29146
    
    int rc = fork();					// 주목
    
    if (rc < 0) {
        exit(1);
    }									// (1) fork 실패
    else if (rc == 0) {					// (2) child 인 경우 (fork 값이 0)
        printf("child (pid : %d)", (int) getpid());
        char *myargs[3];
        myargs[0] = strdup("wc");		// 내가 실행할 파일 이름
        myargs[1] = strdup("p3.c");		// 실행할 파일에 넘겨줄 argument
        myargs[2] = NULL;				// end of array
        execvp(myarges[0], myargs);		// wc 파일 실행.
        printf("this shouldn't print out") // 실행되지 않음.
    }
    else {								// (3) parent case
        int wc = wait(NULL)				// 추가된 부분
        printf("parent of %d (wc : %d / pid : %d)", wc, rc, (int)getpid());
    }
}

exec가 실행되면 execvp(실행파일, 전달 인자) 함수는 code segment 영역에 실행 파일의 코드를 읽어와서 덮어 씌운다. 

 

덮어 씌우게 되면 heap, stack, 다른 메모리 영역이 초기화되고 OS는 그냥 실행한다. 즉, 새로운 Process를 생성하지 않고 현재 프로그램에 wc라는 파일을 실행한다. 따라서 실행 파일이 정상적으로 동작하면 execvp() 이후의 부분을 실행되지 않는다.

728x90
반응형
SMALL