[카테고리:] <span>리눅스 시스템 프로그래밍</span>

앞에서 프로세스를 생성할 때 시스템 호출 fork, vfork 함수를 사용할 수 있다는 것을 얘기했어요. 그리고 부모 프로세스의 많은 부분을 복제하여 자식 프로세스를 생성한다고 하였는데 여기에서는 어떠한 것들을 상속하는지 어떠한 것들을 상속하지 않는지 살펴볼 거예요. 그리고 fork와 vfork 함수에 의해 자식 프로세스를 생성하였을 때 차이점에 알아볼게요.

다음은 fork 함수에 의해 생성한 자식 프로세스가 부모 프로세스로부터 물려받는 속성은 다음과 같습니다.

– 프로그램 이미지, 호출 당시 전역 변수, 지역 변수 값

– 파일 기술자

– 실제 사용자 ID(Real User ID), 실제 그룹 ID(Real Group ID), 유효 그룹 ID(Effective Group ID)

– set user id 플래그, set group id 플래그

– 제어 터미널, 프로세스 그룹 ID, 보조 그룹 ID, 세션 ID

– 현재 작업 디렉토리, 루트 디렉토리

– 파일 모드 생성 마스크, 시그널 마스크

– 환경 변수, 자원 제약

다음은 부모 프로세스와 자식 프로세스가 다른 항목들입니다.

– fork의 반환 값

– 프로세스 ID, 부모 프로세스 ID

– 파일 잠금(file lock)

– 알람과 지연 시그널, 자식은 초기화

– tms_utime, tms_stime, tms_cutime, tms_cstime, 자식은 0으로 초기화

– 파일 디스크립터 테이블(파일 디스크립터를 복제한 값을 갖는다.)

그리고 대부분 fork와 vfork는 수행 결과가 같습니다. 이 두 시스템 호출의 차이는 vfork함수에 의해  새로운 프로세스를 생성하였을 때 부모 프로세스의 메모리 내용을 모두 복사하지 않는다는 점입니다. 자식 프로세스가 exec을 호출하기 전까지는 부모 프로세스의 메모리 공간에서 실행합니다.

이는 vfork는 프로세스를 생성하는 목적이 다른 프로그램 이미지를 갖는 프로세스를 생성하기 위해서입니다. 따라서 vfork로 프로세스를 생성하고 난 후에 exec으로 프로그램 이미지를 교체하여 실행하는 것이 주 목적인 것입니다. 따라서 부모 프로세스의 메모리를 복제하는 것을 생략하는 것입니다. 또한 부모 프로세스는 자식 프로세스가 exec 혹은 exit을 호출하기 전까지 수행하지 않습니다.

이처럼 vfork를 사용하면 context 복사가 일어나지 않고 부모/자식 프로세스 사이에 동기화를 보장할 수 있다는 장점을 갖습니다.

다음은 fork에 의해 자식 프로세스를 생성했을 때 부모 프로세스가 갖고 있는 전역 변수와 지역 변수 값을 복제한다는 것을 확인하는 예제 코드입니다.

/**********************************************************************
* ex_fork2.c                                                          *
* exmple source – compare variable between parent/child process       *
**********************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int gv;
int main()
{
    int lv=0;

    gv=3, lv=2;
    printf("start... gv:%d lv:%d\n",gv,lv);

    pid_t cpid = fork();
    if(cpid == -1)
    {
        perror("error fork");
        return 1;
    }

    if(cpid>0)
    {
        gv++, lv++;
        printf("<parent> gv:%d lv:%d\n",gv,lv);
        printf("<parent> pid:%d ppid:%d\n", getpid(), getppid());
        sleep(1);
    }
    else
    {
        gv++, lv++;
        printf("<child> gv:%d lv:%d\n",gv,lv);
        printf("<child> pid:%d ppid:%d\n", getpid(), getppid());
    }
    return 0;
}
[그림 7.10] ex_fork2 실행 화면
[그림 7.10] ex_fork2 실행 화면

실행 결과를 보면 fork에 의해 생성할 시점에 부모 프로세스의 전역 변수와 지역 변수 값을 복제하는 것을 알 수 있으며 이 후 두 개의 프로세스는 독립된 메모리를 사용함을 알 수 있어요.

리눅스 시스템 프로그래밍