설명

vfork()도 fork()처럼 자식 프로세스를 생성합니다만 다른 점은 fork()가 광역이든 지역이든 메모리 공간까지 똑 같은 복사본을 만들고 부모와 자식이 서로 다른 메모리 공간을 사용하지만 vfork()는 프로세스만 만들고 부모의 메모리 공간을 그대로 이용합니다.

그러므로 부모에서 사용하는 광역변수나 지역변수를 자식에서 사용하면 변경이 되므로 매우 유의해야 합니다.

또한 자식 프로세스가 생성되면 자식 프로세스가 종료될 때까지 부모프로세스는 대기 상태가 됩니다. 즉, 자식 프로세스가 실행이 완료되거나 exit()를 실행하여 종료되거나 exec()를 호출하여 다른 프로그램을 실행하고 종료될 때 까지 부모 프로세스는 대기 상태가 됩니다.

fork()가 프로세스의 주소 공간까지 모두 복사본을 만들기 때문에 시스템 자원에 부담을 주기 때문에 vfork()를 만들었습니다만 기술의 발전으로 fork()의 단점이 보완되었기 때문에 최근에는 vfork()를 사용하지 않습니다. 다만 이전 버전과의 호환성 때문에 존재하고 있으나 부모 프로세스의 주소 공간을 사용하므로 매우 주의해야 합니다. 이런 부담을 피하기 위해서는 fork()를 사용하시는 것이 좋습니다.

아래 프로그램은 vfork()로 자식 프로세스를 생성했고, 자식은 counter 값을 증가 시키고, 부모는 counter값을 감소하고 있습니다. 자식 프로세스는 counter값을 5까지 증가 시키면 종료합니다.

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

int main()
{
   int   counter  = 0;
   pid_t pid;
          
   printf( "작식 프로세스 생성n");          
   pid   = vfork();

   switch( pid)
   {
      case -1  :    
      {
         printf( "자식 프로세스 생성 실패n");
         return -1;
      }      
      case 0   :
      {
         printf( "저는 자식 프로세스로 카운트하겠습니다.n");
         while( counter < 5 )
         {
            printf( "자식: %dn", counter++);                        
            sleep( 1);
         }
      }
      default  :
      {
         printf( "저는 부모 프로세스로 디스카운트하겠습니다.n");
         while( 1 )
         {
            printf( "부모: %dn", counter--);                        
            sleep( 1);
         }
      }
   }
}

이해를 돕기 위에 실행 순서로 본다면 아래와 같습니다.

원래 실행되었던 부모 프로세스 fork()로 생성된 자식 프로세스
int main()
{
   int   counter  = 0;
   pid_t pid;
          
   printf( "작식 프로세스 생성");          
   pid   = fork();
   







---> 자식 프로세스 생성

   switch( pid)
   {
      case -1  :    
      {
         printf( "자식 프로세스 생성 실패n");
         return -1;
      }      
      case 0   :
      {
         printf( "저는 자식 프로세스로....n");
         while( 1 )
         {
            printf( "자식: %dn", counter++);
            sleep( 1);
         }
      }
      default  :
      {
         printf( "저는 부모 프로세스로....n");
         while( 1 )
         {
            printf( "부모: %dn", counter--);
            sleep( 1);
         }
      }
   }
}
// 자식 프로세스의 데이터 영역의 값이 부모
// 프로세스로 복사됩니다.
// 그러므로 위에서 counter을 0 으로 설정했지만
// 자식 프로세스에 의해 counter값이 5가 되었습니다.

   switch( pid)
   {
      case -1  :
      {
         printf( "자식 프로세스 생성 실패n");
         return -1;
      }
      case 0   :
      {
         printf( "저는 자식 프로세스....n");
         while( 1 )
         {
            printf( "자식: %dn", counter++);
            sleep( 1);
         }
      }
      default  :
      {
         printf( "저는 부모 프로세스로...n");
         while( 1 )
         {
            printf( "부모: %dn", counter--);
            sleep( 1);
         }
      }
   }
}

vfork()함수를 호출하고 성공하면 pid 변수값만 다른 완전히 똑 같은 프로세스가 생성됩니다. 그러므로 지금 프로그램이 원래 실행되었던 부모 프로세스인지, 아니면 새로 생성된 자식 프로세스인지는 fork()에서 반환한 값으로 확인합니다.

헤더 unistd.h
형태 pid_t vfork(void);
반환 pid_t 실행에 실패하면 -1 을 반환. 부모에게는 새로 생성된 자식 프로세스 PID가 반환되며, 자식 프로세스에는 0이
반환됩니다.
예제
#include <stdio.h>   
#include <stdlib.h>
#include <unistd.h>

int main()
{
   int   counter  = 0;
   pid_t pid;
          
   printf( "자식 프로세스 생성n");          
   pid   = vfork();

   switch( pid)   // --> 저는 이 부분부터 마음에 들지 않아 vfork()를 사용하지 않습니다.
        왜냐하면 부모와 자식이 모두 같은 메모리 영역을 사용하는데,
        즉 pid값이 부모와 자식이 같은 변수값을 갖게 될텐데,
        신기하게  switch()문에 분리됩니다. 이 부분이 이해가 됩니까?
        저는 이 문서를 작성했지만 이해가 안됩니다.
        실행하면 역시 이해가 안되지만 실행이 됩니다.
        그러나 이런 애매모호한 코딩은 저 개인적으로 매우 싫어합니다.
        학습하는 마음으로 올립니다. 
   {
      case -1  :    
      {
         printf( "자식 프로세스 생성 실패n");
         return -1;
      }      
      case 0   :
      {
         printf( "저는 자식 프로세스로 카운트하겠습니다.n");
         while( counter < 5 )
         {
            printf( "자식: %dn", counter++);                        
            sleep( 1);
         }
      }
      default  :
      {
         printf( "저는 부모 프로세스로 디스카운트하겠습니다.n");
         while( 1 )
         {
            printf( "부모: %dn", counter--);                        
            sleep( 1);
         }
      }
   }
}
]$ ./a.out
자식 프로세스 생성
저는 자식 프로세스로 카운트하겠습니다.
자식: 0
자식: 1
자식: 2
자식: 3
자식: 4
자식 종료
저는 부모 프로세스로 디스카운트하겠습니다.
부모: 5         <-- 역시 5부터 출력됩니다.
부모: 4
부모: 3
부모: 2
부모: 1
부모: 0
부모: -1
부모: -2
부모: -3
부모: -4
부모: -5