본문 바로가기

컴퓨터/언어,프로그래밍

fork()이야기 1.

fork()이야기 1.

pstree 명령어를 아무 생각 없이 쳤다가 fork()를 처음 알게 되었을때가 기억났다. 벌써 몇년의 세월이 흘렀구나...
이넘의 pstree는 손에 붙어 버렸구나. 틈만 나면 치는 구나 ls,w 와 함께 ㅋ
처음 알게 됐을 그땐 참 신기 했었다. 왠지... 내가 유닉스 프로세스를 만든다는게 너무 낯설기도 했고.
티비에서만 보던 연예인이, 같이 지하철을 타고 가는 느낌이었다.

갑자기 그때가 생각 나서 주절 주절...
UNIX에서 멀티테스킹의 기본 단위는 멀티프로세싱이다. 프로세스를 생성 해서 다중 작업을 할 수 있도록 해준다.
프로세스를 생성 하는 방법중 가장 많이 사용되는 방법중에 하나가 fork()를 이용해서 자식 프로세스를 만드는것이다.
처음에 fork()를 알게되었을땐 무척 신기 했다.
fork()를 이용하면 자식 프로세스를 만들어서 부모 프로세스와 다른 작업을 하거나 작업을 나눠 할 수 있게 된다.
물론 이것 때문에 프로세스 통신 이라던가, 시그널이라던가, 세마포어 라던가, 쉐어드 메모리 등 알아야 할것이 많아진다는것을 의미 했다.

처음에는 fork()를 이용하면 자식 프로세스를 만들어서 일을 시키는것인 줄 알았다.
하지만 조금더 알게 되었을때 fork()는 단순히 다른 프로세스를 만든다기 보다, 프로세스 자기 자신을 다른 메모리 영역에 하나더 복제 하는것이라는것을 알게 되었다.
이런 특징으로 인해 몇가지 재미 있는 사용방법이 생긴다.

프로세스 만들기

fork()의 함수 원형은 다음과 같다.
#include
pid_t fork(void);


fork()를 이용해서 차일드 프로세스를 만드는 비교적 간단한다. fork() 함수를 단순히 호출 해주기만 하면된다.
호출된 fork() 함수는 자신의 프로세스를 자식 프로세스로 복제 하면서 자식 프로세스에서는 0을, 부모 프로세스에는 프로세스 번호를 리턴한다.

그러면 생각 해볼 수 있다. 자기 자신과 동일한 프로세스를 생성 한다는것은, 새롭게 생성한 프로세스도 같은 일을 한다는것이다.
물론 fork()를 이용해 자식 프로세스를 생성한 시점 이후부터 같은일을 하게 된다.
그럼, 어떻게 서로 다른 일을 할 수 있을까?
가장 간단한 방법이 리턴된 pid_t 를 이용해서 프로세스를 구분한다음 if를 이용해서 분기 한다.

pid_t childpid; // fork()시 리턴받을 pid_t 타입의 변수를 생성.

childpid = fork(); // childpid 생성.
if (childpid < 0 ) {
perror("fork error"); // 리턴된 pid가 0보다 작을 경우 생성.
}
if ( childpid == 0){
자식 프로세스에서 할일 ;
} else {
부모 프로세스에서 할일;
}


위의 예문처럼 간단하게 프로세스별 작업을 구분 해 줄 수 있다.

기본적인 사용법은 정말 간단하다. 하지만 조금만 생각 하면 꽤나 피곤 해질 수 있다.

프로세스 체인
자식 프로세스, 부모 프로세스를 구분 함으로서 할 수 있는 재미 있는 작업이다.
childpid를 구분함으로서 다중으로 생성되는 프로세스의 체인을 형성 한다.

이 예제는 자식 프로세스에서만 프로세스를 fork() 하도록 한다.

int main (int argc, char *argv[]) {
   pid_t childpid = 0;
   int i, n,k,m;

   if (argc != 2){ 
      fprintf(stderr, "Usage: %s processes\n", argv[0]);
      return 1;
   }
   n = atoi(argv[1]);

   for (i = 1; i < n; i++)
      if (childpid = fork())
         break;

   fprintf(stderr,"i:%d pricess ID:%ld parent ID:%ld child ID:%ld\n",i,(long)getpid(),(long)getppid(),(long)childpid );

   return 0;
}



결과를 돌려 보면,

i:4 pricess ID:12214 parent ID:12213 child ID:0
i:3 pricess ID:12213 parent ID:12212 child ID:12214
i:2 pricess ID:12212 parent ID:12211 child ID:12213
i:1 pricess ID:12211 parent ID:11919 child ID:12212

 

1 -> 2 -> 3 -> 4, 순서로 프로세스 fork() 한다.



즉, 아래의 구문을 둠으로서 부모 프로세스일 경우 break 실행 함으로서 자식 프로세스만 자식 프로세스를 만든다.

      if (childpid = fork())
         break;



반대로, 자식 프로세스에서는 fork()를 하지 않고 부모 프로세스에서만 fork()를 하는 예제도 있다.

int main (int argc, char *argv[]) {
   pid_t childpid = 0;
   int i, n,k,m;

   if (argc != 2){   /* check for valid number of command-line arguments */
      fprintf(stderr, "Usage: %s processes\n", argv[0]);
      return 1;
   }
   n = atoi(argv[1]);


   fprintf(stderr," pricess ID:%ld \n",(long)getpid());


   for (i = 1; i < n; i++)
      if ((childpid = fork()) <= 0)
         break;

   fprintf(stderr,"i:%d pricess ID:%ld parent ID:%ld child ID:%ld\n",i,(long)getpid(),(long)getppid(),(long)childpid );

   return 0;
}


결과를 돌려 보면,

 pricess ID:12276
i:1 pricess ID:12277 parent ID:12276 child ID:0
i:2 pricess ID:12278 parent ID:12276 child ID:0
i:3 pricess ID:12279 parent ID:12276 child ID:0
i:4 pricess ID:12276 parent ID:11919 child ID:12279



이런 결과가 나온다.

4 -> 1
  -> 2
  -> 3


즉, 이런 순서로 자식 프로세스를 fork() 하게 되는것이다. 

별것 아니고... 실제로 많이 쓰이진 않겠지만,
자기 자신의 복제 해서 자식 프로세스를 만드는 방식이라는 점과 부모와 자식 프로세스의 분기라는 점으로 인해 요런 재미 있는 작업이 가능 해진다.

fork()는 부모 프로세스의 복제본이기 때문에 환경변수나 권한을 그대로 가진다.
물론 파일디스크립터나 디바이스 등등 이래저래 많이 상속 받는다. <- 이놈  부자였군..
뭐 반대로 락이나 프로세스 ID나 시그널은 상속 받지 않는다.

물론, 또 재미 있는점이 fork()에서 또 재미 있는 점이 fork()의 시점이다.


출처 : http://onlyperl.egloos.com/4905724

제주삼다수, 2L,... 오뚜기 진라면 매운... 상하목장 유기농 흰... 남양 프렌치카페 카... 고려인삼유통 홍삼 ... 종근당건강 오메가3... 요이치 카링 유무선...