ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C/C++ fork(2)
    C,C++ & Linux 2020. 5. 24. 01:53
    728x90

    함수 기능

    자식 프로세스를 생성해주는 함수입니다.

     

    자식 프로세스는 부모 프로세스의 복사본입니다. 따라서 fork() 이후의 동작은 같은 코드에 의해 동작합니다.

    자식 프로세스는 Stack 영역, Data 영역, Heap 영역에 대해 복사본을 갖기에 둘이 같은 공간을 참조하지는 않지만 Text(Code)영역은 부모 프로세스의 영역을 공유합니다.

    다만 자식 프로세스가 생성될 때부터 Stack, Data, Heap 영역에 대한 복사본을 갖게 되는 것은 아닙니다. fork() 함수 이후에는 exec 계열의 함수를 호출하는 경우가 많기 때문에 미리 복사해두지 않고 부모 프로세스나 자식 프로세스가 Stack, Data, Heap 중 어느 한 곳이라도 수정하게 되는 순간 복사하는 COW(Copy On Write) 정책을 사용합니다. (exec 함수를 쓰게 되면 전혀 다른 프로세스가 되므로 메모리의 복사가 아닌 새로운 메모리의 할당이 필요하므로 비용이 비싼 복사를 하지 않아도 됩니다.)

    함수 원형

    #include <unistd.h>
    
    pid_t fork();

     

    반환값

    성공 시 부모 프로세스에게는 생성된 자식 프로세스의 pid 를 리턴 하고, 자식 프로세스에게는 0을 리턴함

    에러 시 -1 리턴하고 errno 설정

     

    예제

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    char glob_str[] = "write to standard output\n";
    int glob_val = 10;
    
    
    int main(int argc, char *argv[], char *envpp[]) {
        pid_t pid;
        int loc_val;
    
        loc_val = 100;
        if (write(STDOUT_FILENO, glob_str, sizeof(glob_str) - 1) != sizeof(glob_str) - 1) {
            fprintf(stderr, "write error\n");
            exit(1);
        }
    
        printf("before fork\n");
    
        if ((pid = fork()) < 0) {
            fprintf(stderr, "fork error\n");
            exit(1);
        }
        
        // 자식 프로세스
        if (pid == 0) {
            glob_val++;
            loc_val++;
        }
        // 부모 프로세스는 3초 대기
        // 이러면 부모 프로세스는 스케줄링되고, 자식 프로세스가 먼저 실행됨
        else {
            sleep(3);
        }
    
        printf("pid = %d, glob_val = %d, loc_val = %d\n", getpid(), glob_val, loc_val);
        exit(0);
    }
    

     

    결과

    표준 출력 파일이 터미널에 연결되지 않으면 줄 단위 버퍼가 아닌 전체 버퍼를 사용하기 때문에 부모 프로세스에서의 "before fork" 가 버퍼에 담겨있는 상태로 자식프로세스에 그대로 복사됩니다. 따라서 부모 프로세스와 자식 프로세스가 출력 버퍼에 "before fork"를 각각 갖게 되고 두 번 출력되는 것을 볼 수 있습니다.

    참고) write 함수는 None 버퍼입니다.

     

    예제2

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    
    int main(int argc, char *argv[], char *envpp[]) {
        pid_t pid;
        char character, first, last;
        long i;
    
        if ((pid = fork()) < 0) {
            fprintf(stderr, "fork error\n");
            exit(1);
        }
    
        // 부모 프로세스
        if (pid > 0) {
            first = 'A';
            last = 'Z';
        }
    
        // 자식 프로세스
        else {
            first = 'a';
            last = 'z';
        }
    
        for (character = first; character != last; character++) {
            for (i = 0; i <= 100000; i++);
            write(1, &character, 1);
        }
        printf("\n");
        exit(0);
    }
    

    결과

     

    예제3

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    static void ssu_charatatime(char *str) {
        char *ptr;
        int print_char;
    
        setbuf(stdout, NULL);
    
        for (ptr = str; (print_char = *ptr++) != 0;) {
            putc(print_char, stdout);
            usleep(10);
        }
    }
    
    int main(int argc, char *argv[], char *envpp[]) {
        pid_t pid;
    
        if ((pid = fork()) == 0) {
            ssu_charatatime("output from child\n");
        } else if (pid > 0) {
            ssu_charatatime("output from parent\n");
        }
        exit(0);
    }
    

    결과

     

     

     

     

     

     

     

    리눅스시스템프로그래밍 저자 : 홍지만
    https://book.naver.com/bookdb/book_detail.nhn?bid=14623672

    책에 기술된 예제 프로그램입니다. 책 내부에는 훨씬 더 많은 자료가 있습니다. (개인적으로 좋았습니다.)

    'C,C++ & Linux' 카테고리의 다른 글

    C/C++ wait(2), waitpid(2)  (0) 2020.06.04
    C/C++ vfork(2)  (0) 2020.05.24
    C/C++ getpid(2) getppid(2) getuid(2) geteuid(2) getgid(2) getegid(2)  (0) 2020.05.23
    C/C++ setrlimit(2) getrlimit(2)  (0) 2020.05.23
    C/C++ setjmp(3) longjmp(3)  (0) 2020.05.23

    댓글

Designed by Tistory.