본문 바로가기
Study/System Programming

fork 사용하기

by 개발새-발 2021. 10. 17.
반응형

fork를 사용하여 새로운 프로세스를 만들 수 있다. fork() 시스템 콜에 대해 알아보자.

fork

fork를 사용하면 현재 프로세스와 거의 같은 프로세스를 하나 더 생성할 수 있다. 생성된 자식 프로세스의 메모리 영역은 parent process의 메모리 영역을 복사한 것이기 때문에 fork() 이전에 parent process에서 존재하던 어떤 변수를 fork() 이후 child process에서 값을 변화시킨다 하더라도 값이 변하지 않는다. 아래는 fork 시스템 콜에 대한 사용법이다.

  • fork()
    • 인자 : 없음
    • 반환 값
      • 0 : fork()가 성공하면 child process에 반환된다.
      • pid 값 > 0 : fork()가 성공하면 parent process에 생성된 child process의 pid 값이 반환된다.
      • -1 : fork()가 실패하였을 경우 반환된다.

fork 예제 1

아래 fork의 간단한 예제를 확인하자. 아래 예제는 process 하나를 더 생성하여 x를 조작하는 프로그램이다. child process이던, parent process이던 fork()를 한 이후 fork() 의 반환 값을 고려하여 fork() 아래의 코드들을 실행하게 된다. parent process 입장에서는 fork()로부터 child process의 pid 값을 받게 되고, child process는 0을 반환받는다는 것을 기억하면서 아래 코드의 실행 결과를 예측해보자. 참고로 getpid()는 현재 프로세스의 pid 값을 반환한다.

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

int main(void){
    int x = 0;
    pid_t pid;

    if((pid = fork()) == 0){
        // child process (fork() == 0)
        printf("Child pid %d , fork() returned %d\n",getpid(),pid);
        for(int i=1;i<=10;++i){
            x += i;
        }
    }else{
        // parent process of child
        printf("Parent pid %d , fork() returned %d\n",getpid(),pid);
        for(int i=1;i<=10;++i){
            x-=i;
        }

    }

    x += 20;
    printf("pid = %d, x = %d\n",getpid(),x);

    return 0;
}

parent process에서는 x에 1~10의 값을 계속 빼주고, child process에서는 1~10의 값을 계속 더해준다. 그리고 두 프로세스 모두 마지막에 x에 20을 더해준다. 따라서 parent process에서는 x의 값이 -35, child process에서는 75가 된다. 아래는 위 프로그램의 실행 결과이다.

Parent pid 1897 , fork() returned 1898
pid = 1897, x = -35
Child pid 1898 , fork() returned 0
pid = 1898, x = 75

fork() 예제 2

아래 코드는 반복문을 돌리면서 fork()를 수행한다. 반복문이 종료된 후에는 몇 개의 프로세스들이 실행중일까? 참고로 아래 코드에서 getppid()는 parent process의 pid값을 반환한다.

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

int main(void){
    const int N = 3;
    pid_t pid;

    for(int i=0;i<N;++i){
        pid = fork();

        if(pid == 0){
            printf("New child process pid = %d, parent pid %d\n",getpid(),getppid());
        }
    }

    while(1); // never ends
    return 0;
}

정답은 4개가 아닌 8개이다. 위 프로그램을 백그라운드로 실행시킨 후 ps -t로 실행중인 process를 확인해보자.

$ ./manyfork1 &
[1] 2187
$ New child process pid = 2188, parent pid 2187
New child process pid = 2192, parent pid 2188
New child process pid = 2191, parent pid 2188
New child process pid = 2189, parent pid 2187
New child process pid = 2190, parent pid 2187
New child process pid = 2193, parent pid 2191
New child process pid = 2194, parent pid 2189

$ ps -t
  PID TTY      STAT   TIME COMMAND
 2170 pts/1    Ss     0:00 bash
 2187 pts/1    R      0:01 ./manyfork1
 2188 pts/1    R      0:01 ./manyfork1
 2189 pts/1    R      0:01 ./manyfork1
 2190 pts/1    R      0:01 ./manyfork1
 2191 pts/1    R      0:01 ./manyfork1
 2192 pts/1    R      0:01 ./manyfork1
 2193 pts/1    R      0:01 ./manyfork1
 2194 pts/1    R      0:01 ./manyfork1
 2195 pts/1    R+     0:00 ps -t
$ 

처음 실행된 process 이외에 7개의 프로세스가 더 생성되었으며, 백그라운드에서 총 8개의 process가 실행중인 것을 볼 수 있다. 이는 fork()에 의하여 생성된 child process도 반복문을 돌면서 fork()를 호출하여 자신의 child process를 생성하기 때문이다. 따라서, 처음 실행되는 프로세스가 parent process인 child process를 n개 생성하기 위해서는 반복문을 적절하게 탈출해주어야 한다. 아래처럼 반복문 내부에서 child process인 경우 break를 사용하면 반복문이 끝난 후 총 N개의 process만이 더 생성된 것을 볼 수 있다.

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

int main(void){
    const int N = 3;
    pid_t pid;

    for(int i=0;i<N;++i){
        pid = fork();

        if(pid == 0){
            printf("New child process pid = %d, parent pid %d\n",getpid(),getppid());
            break; // break here
        }
    }

    while(1); // never ends
    return 0;
}
$ ./manyfork2 &
[1] 2284
$ New child process pid = 2285, parent pid 2284
New child process pid = 2286, parent pid 2284
New child process pid = 2287, parent pid 2284

$ ps -t
  PID TTY      STAT   TIME COMMAND
 2270 pts/0    Ss     0:00 bash
 2284 pts/0    R      0:01 ./manyfork2
 2285 pts/0    R      0:01 ./manyfork2
 2286 pts/0    R      0:01 ./manyfork2
 2287 pts/0    R      0:01 ./manyfork2
 2288 pts/0    R+     0:00 ps -t
$ 
반응형

'Study > System Programming' 카테고리의 다른 글

lseek, pread, pwrite 사용하기  (0) 2021.11.17
open, read, write, close 사용하기  (0) 2021.11.15
wait, waitpid의 사용  (0) 2021.10.19
sigprocmask을 사용하여 signal block 하기  (0) 2021.10.16

댓글