프로세스와 관련한 더 많은 정보와 예제를 담은 리눅스 교재를 배포했습니다. 아래의 페이지에서 리눅스 교재를 받아가세요.

https://reakwon.tistory.com/233

 

리눅스 프로그래밍 note 배포

티스토리에 리눅스에 관한 내용을 두서없이 여지껏 포스팅했었데요. 저도 제 포스팅을 찾기가 어렵기도 하고 티스토리에서 코드삽입을 하게 되면 이게 일자로 쭉 쓰여져있는 x같은 현상이 생겨

reakwon.tistory.com

 

wait, waitpid 함수는 아래의 header파일을 include해야합니다. 이 두 함수는 부모프로세스가 자식프로세스를 기다리는 공통점이 있습니다만 waitpid는 어떤 자식을 기다릴지 조금 더 구체적으로 지정할 수 있습니다.

이 두 함수의 반환값은 성공시 process id를 반환하고 오류시 -1을 반환합니다. 

#include <sys/types.h>
#include <sys/wait.h>

 

wait 함수

pid_t wait(int *wstatus);

 

성공시 프로세스의 pid를 반환합니다. wstatus는 종료상태를 알 수 있는데, 굳이 종료상태를 알 필요가 없다면 NULL을 전달해주세요.

wstatus를 알 수 있는 방법은 <sys/wait.h>에 정의되어있는 매크로들을 사용하면 됩니다. 아래는 그 매크로들과 설명입니다. 

매크로 설명
WIFEXITED(wstatus) returns  true  if  the  child  terminated normally, that is, by calling exit(3) or
              _exit(2), or by returning from main().
WEXITSTATUS(wstatus) returns the exit status of the child.  This consists of the  least  significant  8
              bits  of  the  status  argument  that  the child specified in a call to exit(3) or
              _exit(2) or as the argument for a return statement in main().  This  macro  should
              be employed only if WIFEXITED returned true.
WIFSIGNALED(wstatus) returns true if the child process was terminated by a signal.
WTERMSIG(wstatus) returns the number of the signal that caused the child process to terminate.  This
              macro should be employed only if WIFSIGNALED returned true.
 WCOREDUMP(wstatus) returns true if the child produced a core dump.  This  macro  should  be  employed
              only if WIFSIGNALED returned true.

              This  macro  is  not  specified  in POSIX.1-2001 and is not available on some UNIX
              implementations (e.g., AIX, SunOS).  Therefore,  enclose  its  use  inside  #ifdef
              WCOREDUMP ... #endif.
WIFSTOPPED(wstatus) returns  true  if  the  child process was stopped by delivery of a signal; this is
              possible only if the call was done using WUNTRACED or  when  the  child  is  being
              traced (see ptrace(2)).
WSTOPSIG(wstatus) returns  the  number  of  the  signal  which caused the child to stop.  This macro
              should be employed only if WIFSTOPPED returned true.
 WIFCONTINUED(wstatus) (since Linux 2.6.10) returns true if the child process was resumed by delivery  of
              SIGCONT

 

그렇다면 이제 예제를 보도록 하겠습니다.

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
        int status, cpid, endpid;

        if((cpid=fork())==0){
                printf("\tchild process:%d\n",getpid());
                sleep(10);
                printf("\tchild end\n");
                exit(10);
        }

        endpid=wait(&status);
        printf("end pid : %d\n",endpid);
        printf("WIFEXITED : %d\n",WIFEXITED(status));
        printf("WEXITSTATUS : %d\n",WEXITSTATUS(status));
        printf("WIFSIGNALED : %d\n",WIFSIGNALED(status));

        printf("\n");
        printf("parent end\n");

}

 

이후 아래와 같이 컴파일하고 정상적인 결과를 보도록 해봅시다.

# gcc process_wait.c
# ./a.out
        child process:5031
        child end
end pid : 5031
WIFEXITED : 1
WEXITSTATUS : 10
WIFSIGNALED : 0

parent end

 

EXITSTATUS는 10임을 알 수 있는데 이는 위 코드에서 exit(10)을 사용했기 때문입니다. 시그널을 받지 않고 정상적인 종료를 한 케이스는 이렇게 나오는군요.

이제 background로 프로세스를 돌리고 kill해서 시그널을 보내보도록 하겠습니다.

# ./a.out &
[4] 5060
#     child process:5061

# kill 5061
# end pid : 5061
WIFEXITED : 0
WEXITSTATUS : 0
WIFSIGNALED : 1

parent end

[4]+  Done                    ./a.out

 

그렇다면 WIFEXITED는 false이고 WIFSIGNALED는 true네요. 이처럼 위의 매크로로 자식 프로세스의 종료 상태를 알 수 있습니다.

그런데 wait은 종료되는 자식 프로세스 중 먼저 종료되는 프로세스가 있다면 바로 호출되어지는데 만약 우리가 특정 자식프로세스만을 기다린다할때는 아래의 waitpid함수를 사용해야합니다.

 

waitpid

pid_t waitpid(pid_t pid, int *wstatus, int options);

역시 호출 성공시 그 프로세스의 pid, 아니라면 -1을 반환합니다. 

pid: 인자로 pid는 기다릴 프로세스 식별자인데 양수일 경우만 해당합니다. 아래는 pid에 따라서 어떻게 동작하는지를 설명합니다.

 

pid 설명
< -1  meaning wait for any child process whose process group ID is equal to the absolute value of pid. 
 -1 meaning wait for any child process. 
0 meaning wait for any child process whose process group ID is equal to that of  the calling process.
> 0  meaning wait for the child whose process ID is equal to the value of pid. 

 

wstatus : wstatus는 위의 wait과 같이 종지상태를 얻어옵니다.

option : option은 조금 더 구체적인 동작을 지정합니다. option의 종류는 아래와 같습니다.

 

OPTION 설명
WNOHANG return immediately if no child has exited. 
WUNTRACED also  return  if  a child has stopped (but not traced via ptrace(2)).  Status for traced children which have stopped is provided even if this option is not specified. 
WCONTINUED (since Linux 2.6.10) also return if a stopped child has been resumed by delivery of SIGCONT. 

 

wait(&status)은 waitpid(-1, &wstatus, 0)를 호출한 것과 같습니다.

 

waitpid 예제

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
        int state, cpid1, cpid2, endpid;

        if((cpid1=fork())==0){
                printf("\tchild1 process:%d\n",getpid());
                sleep(2);
                printf("\tchild1 end\n");
                exit(0);
        }

        if((cpid2=fork())==0){
                printf("\tchild2 process:%d\n",getpid());
                sleep(4);
                printf("\tchild2 end\n");
                exit(0);
        }

        endpid=waitpid(cpid1,&state,0);
        printf("pid : %d\n",endpid);

        endpid=waitpid(cpid2,&state,0);
        printf("pid : %d\n",endpid);


        printf("parent end\n");

}

 

여기서 자식 프로세스를 2개 생성하고 기다리는데 waitpid로 첫번째 자식 프로세스, 두번째 자식 프로세스를 기다립니다. 만약 여기서 두 번째 자식 프로세스를 기다리고 싶지 않다면 두 번째 waitpid를 하지 않으면 되겠죠.

결과는 아래와 같습니다.

#gcc process_waitpid.c
# ./a.out
        child2 process:5614
        child1 process:5613
        child1 end
pid : 5613
        child2 end
pid : 5614
parent end

 

 

만약 두번째 프로세스가 끝났을때는 그대로 종료하지만 작업이 끝나지 않았을때는 A라는 작업을 해야하는 상황이라면 어떻게 해야할까요? 

wait은 계속 자식 프로세스가 끝날때까지 block되었는데 waitpid는 옵션을 사용하면 됩니다. 

 

아래가 그 예제입니다.

 

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
        int state, cpid1, cpid2, endpid;

        if((cpid1=fork())==0){
                printf("\tchild1 process:%d\n",getpid());
                sleep(2);
                printf("\tchild1 end\n");
                exit(0);
        }

        if((cpid2=fork())==0){
                printf("\tchild2 process:%d\n",getpid());
                sleep(4);
                printf("\tchild2 end\n");
                exit(0);
        }

        while(1){
                endpid=waitpid(cpid2,&state,WNOHANG);
                if(endpid==0){  //child not finished if pid = 0
                        printf("child2 not finished\n");
                        sleep(1);
                }else{
                        break;
                }

        }

        printf("parent end\n");

}

 

위 코드에서는 첫번째 자식 프로세스는 기다리지 않습니다. waitpid에 WNOHANG 옵션을 주어서 자식이 종료되었는지 아닌지에 따라 작업을 구분지을 수 있습니다. 이때 waitpid는 지정된 프로세스가 끝나지 않았다면 0을 반환하고 끝났다면 그 pid를 반환하게 됩니다.

결과는 아래와 같습니다.

# gcc process_waitpid2.c
# ./a.out
child2 not finished
        child2 process:5670
        child1 process:5669
child2 not finished
        child1 end
child2 not finished
child2 not finished
        child2 end
parent end

 

waitpid가 wait에서 제공하지 못하는 3가지를 제공합니다.

1. waitpid함수로 특정 pid를 기다릴 수 있습니다. wait은 임의의 자식에 대해서 종료상태를 알려주지요.

2. waitpid는 wait과는 달리 자식이 종료될때까지 기다리지 않아도 됩니다. 바로 호출을 할 수 있습니다.

3. WUNTRACED와 WCONTINUED 옵션을 통해서 작업 제어를 할 수 있습니다.

 

 

 

반응형
블로그 이미지

REAKWON

와나진짜

,