C 언어에서 wait()와 waitpid()를 사용한 자식 프로세스 제어 방법

C 언어에서 프로세스 제어는 운영체제와의 상호작용을 통해 프로그램의 동작을 관리하는 핵심 요소입니다. 특히 부모 프로세스가 자식 프로세스의 상태를 제어하는 방법은 시스템 프로그래밍에서 자주 사용됩니다. 본 기사에서는 wait()waitpid() 함수의 개념과 활용법을 통해 부모-자식 프로세스 간의 작업을 효과적으로 조정하는 방법을 알아봅니다. 이를 통해 좀비 프로세스를 방지하고 시스템 자원을 효율적으로 사용하는 프로세스 제어 기법을 익힐 수 있습니다.

프로세스 생성과 부모-자식 관계

fork() 함수와 프로세스 생성


C 언어에서 새로운 프로세스를 생성하려면 fork() 함수를 사용합니다. fork()는 현재 실행 중인 프로세스를 복제하여 두 개의 프로세스를 생성하며, 이들은 각각 부모 프로세스와 자식 프로세스로 구분됩니다.

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

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        printf("This is the child process.\n");
    } else if (pid > 0) {
        printf("This is the parent process. Child PID: %d\n", pid);
    } else {
        perror("fork failed");
    }

    return 0;
}

부모와 자식 프로세스의 관계


fork() 호출 후 반환값에 따라 부모와 자식 프로세스는 서로 다른 코드를 실행합니다.

  • 부모 프로세스: fork()가 자식 프로세스의 PID(프로세스 ID)를 반환.
  • 자식 프로세스: fork()가 0을 반환.

부모 프로세스는 일반적으로 자식 프로세스를 생성한 후 종료 상태를 모니터링하거나 작업을 조율합니다. 반면, 자식 프로세스는 자신만의 작업을 독립적으로 수행할 수 있습니다.

프로세스 ID와 부모-자식 연결


각 프로세스는 고유한 PID를 가지며, 부모-자식 관계는 부모 PID(getppid())와 자식 PID(getpid())를 통해 확인할 수 있습니다. 이를 통해 부모-자식 간의 작업 흐름을 제어할 수 있습니다.

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

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        printf("Child Process: PID=%d, Parent PID=%d\n", getpid(), getppid());
    } else if (pid > 0) {
        printf("Parent Process: PID=%d\n", getpid());
    }

    return 0;
}

wait() 함수의 기본 개념과 사용법

wait() 함수란?


wait() 함수는 부모 프로세스가 자식 프로세스의 종료를 기다리도록 하는 시스템 호출입니다. 자식 프로세스가 종료될 때까지 부모 프로세스는 실행을 중단하고 대기 상태에 들어갑니다. 이 함수는 종료된 자식 프로세스의 정보를 반환하며, 기본적으로 좀비 프로세스의 생성을 방지합니다.

wait() 함수의 반환값

  • 정상적인 실행 시 종료된 자식 프로세스의 PID(프로세스 ID)를 반환합니다.
  • 에러 발생 시 -1을 반환하며, 이 경우 errno를 통해 오류 원인을 확인할 수 있습니다.

사용 예제

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

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        // 자식 프로세스
        printf("Child Process: PID=%d\n", getpid());
        sleep(2); // 작업 시뮬레이션
        return 42; // 종료 상태
    } else if (pid > 0) {
        // 부모 프로세스
        int status;
        pid_t child_pid = wait(&status); // 자식 종료 대기

        if (WIFEXITED(status)) {
            printf("Parent Process: Child %d exited with status %d\n", child_pid, WEXITSTATUS(status));
        }
    } else {
        perror("fork failed");
    }

    return 0;
}

WIFEXITED와 WEXITSTATUS

  • WIFEXITED(status): 자식 프로세스가 정상적으로 종료되었는지 확인합니다.
  • WEXITSTATUS(status): 자식 프로세스의 종료 코드를 반환합니다.

위 예제에서 wait()를 통해 자식 프로세스의 종료를 기다리고, 종료 상태를 확인할 수 있습니다.

wait() 함수의 동작 원리

  • 부모 프로세스는 자식 프로세스가 종료될 때까지 대기합니다.
  • 자식 프로세스가 종료되면 부모 프로세스는 해당 자식 프로세스의 종료 상태를 회수(collect)합니다.
  • 대기 중인 자식 프로세스가 없을 경우 wait()는 즉시 반환됩니다.

사용 시 주의사항


wait() 함수는 종료된 자식 프로세스 하나에 대해서만 동작합니다. 다수의 자식 프로세스를 관리해야 할 경우 여러 번 호출하거나 waitpid() 함수를 사용해야 합니다.

waitpid() 함수의 고급 활용

waitpid() 함수란?


waitpid() 함수는 wait() 함수의 확장된 형태로, 특정 자식 프로세스를 기다릴 수 있도록 설계되었습니다. 이 함수는 자식 프로세스의 상태를 확인하거나 종료를 대기하는 데 유용하며, 비동기 처리와 같은 고급 시나리오에서 효과적입니다.

waitpid() 함수의 시그니처

pid_t waitpid(pid_t pid, int *status, int options);
  • pid: 대기할 자식 프로세스의 PID를 지정합니다.
  • >0: 특정 자식 프로세스의 PID.
  • -1: 모든 자식 프로세스. (wait()와 동일한 동작)
  • 0: 동일한 프로세스 그룹의 모든 자식 프로세스.
  • <-1: 절대값을 프로세스 그룹 ID로 간주.
  • status: 자식 프로세스의 종료 상태를 저장할 포인터.
  • options: 추가 옵션. 예를 들어, WNOHANG(비동기 대기).

기본 사용 예제

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

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        // 자식 프로세스
        printf("Child Process: PID=%d\n", getpid());
        sleep(2); // 작업 시뮬레이션
        return 42; // 종료 상태
    } else if (pid > 0) {
        // 부모 프로세스
        int status;
        pid_t child_pid = waitpid(pid, &status, 0); // 특정 자식 프로세스 대기

        if (WIFEXITED(status)) {
            printf("Parent Process: Child %d exited with status %d\n", child_pid, WEXITSTATUS(status));
        }
    } else {
        perror("fork failed");
    }

    return 0;
}

비동기 처리: WNOHANG 옵션


WNOHANG 옵션은 자식 프로세스가 종료되지 않아도 즉시 반환되도록 합니다.

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

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        // 자식 프로세스
        printf("Child Process: PID=%d\n", getpid());
        sleep(2); // 작업 시뮬레이션
        return 42; // 종료 상태
    } else if (pid > 0) {
        // 부모 프로세스
        int status;
        pid_t result;

        do {
            result = waitpid(pid, &status, WNOHANG); // 비동기 대기
            if (result == 0) {
                printf("Child is still running...\n");
                sleep(1);
            }
        } while (result == 0);

        if (WIFEXITED(status)) {
            printf("Parent Process: Child %d exited with status %d\n", pid, WEXITSTATUS(status));
        }
    } else {
        perror("fork failed");
    }

    return 0;
}

waitpid()와 wait()의 차이

  • 대상 지정: waitpid()는 특정 자식 프로세스를 지정 가능, wait()는 모든 자식 프로세스 중 하나.
  • 옵션 지원: waitpid()WNOHANG, WUNTRACED 등 옵션을 지원하여 유연한 대기 가능.
  • 동기/비동기: waitpid()는 비동기 대기를 지원.

활용 시나리오

  1. 여러 자식 프로세스 중 특정 프로세스의 종료를 대기해야 할 때.
  2. 비동기 대기를 통해 부모 프로세스가 다른 작업을 수행하도록 할 때.
  3. 프로세스 그룹 단위로 작업을 조율할 때.

부모 프로세스가 자식 종료 상태 확인하기

자식 프로세스의 종료 상태란?


부모 프로세스는 자식 프로세스가 종료될 때 상태 정보를 얻을 수 있습니다. 이 상태 정보에는 자식 프로세스의 종료 코드, 종료 원인, 또는 신호에 의한 종료 여부가 포함됩니다.

상태 정보 확인 매크로


wait() 또는 waitpid()가 반환하는 status 값은 매크로를 사용해 분석할 수 있습니다.

  • WIFEXITED(status): 자식 프로세스가 정상적으로 종료되었는지 확인.
  • WEXITSTATUS(status): 자식 프로세스의 종료 코드 확인.
  • WIFSIGNALED(status): 자식 프로세스가 신호에 의해 종료되었는지 확인.
  • WTERMSIG(status): 자식 프로세스를 종료시킨 신호 번호 확인.
  • WIFSTOPPED(status): 자식 프로세스가 멈췄는지 확인(디버깅 목적).
  • WSTOPSIG(status): 자식 프로세스를 멈춘 신호 번호 확인.

사용 예제

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

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        // 자식 프로세스
        printf("Child Process: PID=%d\n", getpid());
        sleep(2); // 작업 시뮬레이션
        return 42; // 종료 코드
    } else if (pid > 0) {
        // 부모 프로세스
        int status;
        pid_t child_pid = wait(&status);

        if (WIFEXITED(status)) {
            printf("Parent Process: Child %d exited normally with status %d\n", child_pid, WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("Parent Process: Child %d was terminated by signal %d\n", child_pid, WTERMSIG(status));
        } else if (WIFSTOPPED(status)) {
            printf("Parent Process: Child %d was stopped by signal %d\n", child_pid, WSTOPSIG(status));
        }
    } else {
        perror("fork failed");
    }

    return 0;
}

상태 매크로의 동작 방식

  • WIFEXITED: 자식 프로세스가 exit() 또는 return으로 종료된 경우 true를 반환합니다.
  • WEXITSTATUS: 자식 프로세스가 종료 시 반환한 값을 제공합니다(0~255 사이).
  • WIFSIGNALED: 자식 프로세스가 신호에 의해 종료된 경우 true를 반환합니다.

응용 시나리오

  1. 자식 프로세스가 예상대로 작업을 완료했는지 확인.
  2. 프로세스 종료 시 실패 원인을 분석.
  3. 디버깅 중 멈춘 프로세스를 조사.

실제 활용 예제: 작업 실패 처리

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

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        // 자식 프로세스: 강제 종료 시뮬레이션
        printf("Child Process: Simulating failure\n");
        exit(1); // 비정상 종료
    } else if (pid > 0) {
        // 부모 프로세스
        int status;
        pid_t child_pid = wait(&status);

        if (WIFEXITED(status)) {
            if (WEXITSTATUS(status) == 0) {
                printf("Child %d completed successfully.\n", child_pid);
            } else {
                printf("Child %d failed with exit code %d.\n", child_pid, WEXITSTATUS(status));
            }
        }
    }

    return 0;
}

이와 같이 자식 프로세스의 종료 상태를 확인하여 성공 여부를 평가하거나 적절한 후속 조치를 수행할 수 있습니다.

wait()와 waitpid()의 차이점

기능적 차이


wait()waitpid()는 모두 부모 프로세스가 자식 프로세스의 종료를 대기하는 함수이지만, 동작 방식과 유연성에서 차이가 있습니다.

특징wait()waitpid()
대상 지정모든 자식 프로세스 중 하나특정 자식 프로세스를 지정 가능
옵션 지원지원하지 않음WNOHANG, WUNTRACED 등 옵션 지원
비동기 처리불가능가능 (예: WNOHANG)
반환값종료된 자식 프로세스의 PID종료된 자식 프로세스의 PID (또는 비동기 처리 결과)
동작 방식자식 프로세스 하나가 종료될 때까지 대기동기/비동기 선택 가능, 유연한 대기 수행

wait()의 특징


wait() 함수는 모든 자식 프로세스 중 하나가 종료될 때까지 대기합니다.

  • 장점: 간단한 구현으로 모든 자식 프로세스를 기다릴 수 있습니다.
  • 단점: 특정 자식 프로세스를 제어하거나 비동기 작업을 처리할 수 없습니다.

예제

pid_t pid = wait(&status);
printf("Child Process with PID %d terminated.\n", pid);

waitpid()의 특징


waitpid()는 특정 자식 프로세스를 선택적으로 대기할 수 있으며, 추가 옵션을 통해 비동기 처리도 가능합니다.

  • 장점: 특정 자식 프로세스 대기, 비동기 처리 가능, 옵션을 통한 고급 제어.
  • 단점: wait()에 비해 상대적으로 복잡한 구현.

예제

pid_t pid = waitpid(target_pid, &status, WNOHANG);
if (pid == 0) {
    printf("Child process is still running.\n");
} else {
    printf("Child Process with PID %d terminated.\n", pid);
}

사용 시나리오 비교

  1. wait() 적합 사례
  • 간단한 프로그램에서 모든 자식 프로세스의 종료를 기다릴 때.
  • 비동기 작업이 필요하지 않을 때.
  1. waitpid() 적합 사례
  • 특정 자식 프로세스만 선택적으로 대기해야 할 때.
  • 비동기 처리나 여러 자식 프로세스의 병렬 작업을 처리할 때.
  • 좀비 프로세스를 방지하면서 부모 프로세스가 다른 작업을 수행해야 할 때.

실제 활용 예제


아래는 여러 자식 프로세스를 생성하고 waitpid()를 사용해 각각의 종료 상태를 관리하는 예제입니다.

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

int main() {
    pid_t pids[3];
    for (int i = 0; i < 3; i++) {
        pids[i] = fork();
        if (pids[i] == 0) {
            // 각 자식 프로세스 작업
            printf("Child Process %d: PID=%d\n", i, getpid());
            sleep(2 + i); // 작업 시뮬레이션
            exit(i); // 종료 코드
        }
    }

    // 부모 프로세스: waitpid()로 각 자식 프로세스 대기
    for (int i = 0; i < 3; i++) {
        int status;
        pid_t child_pid = waitpid(pids[i], &status, 0);
        if (WIFEXITED(status)) {
            printf("Parent: Child %d with PID %d exited with status %d.\n", i, child_pid, WEXITSTATUS(status));
        }
    }

    return 0;
}

이처럼 wait()waitpid()는 목적에 따라 선택하여 사용할 수 있으며, waitpid()는 복잡한 상황에서 유연한 제어를 가능하게 합니다.

비동기 자식 프로세스 처리 방법

비동기 처리란?


비동기 처리에서는 부모 프로세스가 자식 프로세스의 종료를 기다리지 않고 다른 작업을 병행할 수 있습니다. 이를 위해 waitpid() 함수에서 WNOHANG 옵션을 사용합니다. 이 옵션은 자식 프로세스가 아직 종료되지 않은 경우 즉시 반환하도록 합니다.

WNOHANG 옵션의 동작

  • 자식 프로세스가 종료되지 않았을 경우 waitpid()는 0을 반환합니다.
  • 자식 프로세스가 종료된 경우 종료된 프로세스의 PID를 반환합니다.

비동기 처리 예제

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

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        // 자식 프로세스
        printf("Child Process: PID=%d\n", getpid());
        sleep(5); // 작업 시뮬레이션
        return 42; // 종료 코드
    } else if (pid > 0) {
        // 부모 프로세스
        int status;
        while (1) {
            pid_t result = waitpid(pid, &status, WNOHANG); // 비동기 대기
            if (result == 0) {
                printf("Parent Process: Child is still running...\n");
                sleep(1); // 다른 작업 수행
            } else if (result > 0) {
                if (WIFEXITED(status)) {
                    printf("Parent Process: Child exited with status %d\n", WEXITSTATUS(status));
                }
                break;
            } else {
                perror("waitpid failed");
                break;
            }
        }
    } else {
        perror("fork failed");
    }

    return 0;
}

비동기 처리의 장점

  1. 효율적인 자원 활용: 부모 프로세스가 대기하는 동안 다른 작업을 수행 가능.
  2. 실시간 상태 확인: 자식 프로세스의 진행 상태를 주기적으로 확인 가능.
  3. 유연성 증가: 여러 자식 프로세스가 있을 때 비동기로 관리 가능.

다중 자식 프로세스의 비동기 처리


WNOHANG을 사용하면 여러 자식 프로세스를 비동기로 처리할 수 있습니다.

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

int main() {
    pid_t pids[3];
    for (int i = 0; i < 3; i++) {
        pids[i] = fork();
        if (pids[i] == 0) {
            printf("Child Process %d: PID=%d\n", i, getpid());
            sleep(3 + i); // 작업 시뮬레이션
            exit(i); // 종료 코드
        }
    }

    // 부모 프로세스: 비동기로 자식 프로세스 관리
    int status;
    while (1) {
        int active = 0;
        for (int i = 0; i < 3; i++) {
            pid_t result = waitpid(pids[i], &status, WNOHANG);
            if (result == 0) {
                active++;
            } else if (result > 0) {
                if (WIFEXITED(status)) {
                    printf("Parent: Child %d (PID=%d) exited with status %d.\n", i, result, WEXITSTATUS(status));
                }
            }
        }
        if (active == 0) break; // 모든 자식 프로세스 종료 시 루프 종료
        sleep(1); // 다른 작업 수행
    }

    return 0;
}

주의사항

  • 비동기 처리는 코드가 복잡해질 수 있으므로 필요에 따라 신중히 사용해야 합니다.
  • 자식 프로세스가 너무 많을 경우 반복적으로 상태를 확인하는 루프에서 CPU 사용량이 증가할 수 있습니다.

활용 시나리오

  1. 부모 프로세스가 주기적으로 자식 프로세스 상태를 확인해야 할 때.
  2. 대기 중에도 다른 작업을 수행해야 할 때(예: 이벤트 처리, 데이터 송수신).
  3. 여러 자식 프로세스를 효율적으로 관리하면서 부모 프로세스의 작업 흐름을 유지해야 할 때.

wait()와 waitpid()로 좀비 프로세스 방지

좀비 프로세스란?


좀비 프로세스는 종료된 자식 프로세스의 PID와 종료 상태가 부모 프로세스에 의해 회수되지 않고 운영체제의 프로세스 테이블에 남아 있는 상태를 말합니다. 좀비 프로세스는 시스템 리소스를 차지하기 때문에 관리되지 않으면 심각한 문제를 일으킬 수 있습니다.

좀비 프로세스가 발생하는 이유

  1. 자식 프로세스가 종료되었지만 부모 프로세스가 wait() 또는 waitpid()를 호출하지 않은 경우.
  2. 부모 프로세스가 자식 프로세스의 종료 상태를 회수하지 않고 무기한 대기하거나 무시한 경우.

wait()와 waitpid()를 활용한 방지 방법

  1. 자식 프로세스의 종료 상태 회수
    부모 프로세스는 wait() 또는 waitpid()를 사용해 자식 프로세스의 종료 상태를 확인하고 좀비 프로세스를 제거해야 합니다.
   int status;
   pid_t child_pid = wait(&status); // 종료된 자식 프로세스 회수
  1. 비동기 상태 확인
    WNOHANG 옵션을 사용하면 부모 프로세스는 자식 프로세스가 종료되지 않아도 다른 작업을 수행할 수 있습니다. 이를 통해 부모 프로세스가 좀비 프로세스를 방지하면서 유연하게 동작할 수 있습니다.
   int status;
   pid_t child_pid = waitpid(-1, &status, WNOHANG);

실제 사용 예제

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

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        // 자식 프로세스
        printf("Child Process: PID=%d\n", getpid());
        sleep(2); // 작업 시뮬레이션
        exit(0); // 정상 종료
    } else if (pid > 0) {
        // 부모 프로세스
        printf("Parent Process: Monitoring child...\n");
        int status;
        pid_t child_pid = wait(&status); // 자식 프로세스 종료 대기

        if (WIFEXITED(status)) {
            printf("Parent Process: Child %d exited with status %d\n", child_pid, WEXITSTATUS(status));
        }
    } else {
        perror("fork failed");
    }

    return 0;
}

부모 프로세스가 종료되는 경우


부모 프로세스가 종료되면 고아 프로세스가 되어 자동으로 init 프로세스(보통 PID 1)가 부모가 됩니다. init 프로세스는 자동으로 자식 프로세스의 상태를 회수하므로 좀비 프로세스는 발생하지 않습니다.

시그널 핸들러를 이용한 좀비 프로세스 방지


부모 프로세스가 시그널 핸들러를 사용해 자식 프로세스의 종료를 자동으로 처리할 수 있습니다.

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

void handle_sigchld(int sig) {
    while (waitpid(-1, NULL, WNOHANG) > 0); // 모든 종료된 자식 프로세스 회수
}

int main() {
    signal(SIGCHLD, handle_sigchld); // SIGCHLD 시그널 처리

    for (int i = 0; i < 3; i++) {
        if (fork() == 0) {
            printf("Child Process: PID=%d\n", getpid());
            sleep(2); // 작업 시뮬레이션
            exit(0); // 정상 종료
        }
    }

    while (1) {
        printf("Parent Process: Running...\n");
        sleep(1); // 부모 프로세스의 다른 작업
    }

    return 0;
}

요약

  • wait()waitpid()는 부모 프로세스가 자식 프로세스의 종료 상태를 회수하여 좀비 프로세스를 방지하는 데 필수적입니다.
  • 비동기 처리(WNOHANG)와 시그널 핸들러를 활용하면 좀비 프로세스를 효율적으로 관리할 수 있습니다.
  • 부모 프로세스는 자식 프로세스를 적절히 관리하여 시스템 리소스를 보호해야 합니다.

연습 문제와 응용 예제

연습 문제

  1. 기본 프로세스 생성 및 종료 상태 확인
  • fork()를 사용해 자식 프로세스를 생성하고, 부모 프로세스가 자식 프로세스의 종료 상태를 확인하는 프로그램을 작성하세요.
  • 자식 프로세스는 간단한 작업을 수행하고 종료 상태로 42를 반환해야 합니다.
  1. 비동기 대기와 상태 출력
  • 부모 프로세스가 비동기로 자식 프로세스를 대기하며 자식의 상태를 주기적으로 출력하는 프로그램을 작성하세요.
  • WNOHANG 옵션을 사용하고, 자식 프로세스가 종료될 때까지 부모 프로세스가 “Child is still running…”을 출력해야 합니다.
  1. 좀비 프로세스 방지 시그널 핸들러
  • SIGCHLD 신호를 처리하여 종료된 모든 자식 프로세스를 회수하는 프로그램을 작성하세요.
  • 부모 프로세스는 종료되지 않고 계속 실행되며, 자식 프로세스는 3개 생성되어 각각 다른 종료 상태를 반환해야 합니다.

응용 예제

  1. 멀티프로세싱 계산 작업 분배
    아래 프로그램은 부모 프로세스가 여러 자식 프로세스를 생성해 계산 작업을 분배하고 결과를 수집하는 예제입니다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main() {
    int n = 3; // 작업 수
    pid_t pids[n];

    for (int i = 0; i < n; i++) {
        pids[i] = fork();
        if (pids[i] == 0) {
            // 자식 프로세스: 계산 작업
            int result = (i + 1) * 10;
            printf("Child %d: Calculated result = %d\n", i, result);
            exit(result); // 결과 반환
        }
    }

    // 부모 프로세스: 결과 수집
    for (int i = 0; i < n; i++) {
        int status;
        pid_t pid = waitpid(pids[i], &status, 0);
        if (WIFEXITED(status)) {
            printf("Parent: Child %d (PID=%d) returned result = %d\n", i, pid, WEXITSTATUS(status));
        }
    }

    return 0;
}
  1. 웹 서버 프로세스 시뮬레이션
    부모 프로세스는 클라이언트 요청을 처리하기 위해 자식 프로세스를 생성하고, 모든 요청이 완료될 때까지 기다립니다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void handle_request(int client_id) {
    printf("Handling request from client %d\n", client_id);
    sleep(2); // 요청 처리 시뮬레이션
    printf("Request from client %d completed\n", client_id);
    exit(0); // 정상 종료
}

int main() {
    int num_clients = 3;
    pid_t pids[num_clients];

    for (int i = 0; i < num_clients; i++) {
        pids[i] = fork();
        if (pids[i] == 0) {
            handle_request(i + 1); // 자식 프로세스에서 요청 처리
        }
    }

    // 부모 프로세스: 모든 자식 프로세스 대기
    for (int i = 0; i < num_clients; i++) {
        int status;
        pid_t pid = waitpid(pids[i], &status, 0);
        if (WIFEXITED(status)) {
            printf("Parent: Client %d request handled successfully (PID=%d)\n", i + 1, pid);
        }
    }

    return 0;
}

응용 아이디어

  • 파일 처리 작업: 여러 자식 프로세스를 생성해 각각 다른 파일을 처리하고 부모 프로세스가 결과를 수집.
  • 데이터베이스 병렬 쿼리 실행: 자식 프로세스가 각각 독립적으로 쿼리를 실행하고 결과를 부모 프로세스가 집계.
  • 비디오 프레임 처리: 자식 프로세스가 프레임을 병렬로 처리하고 결과를 부모 프로세스가 합성.

이 연습 문제와 예제는 프로세스 생성, 제어, 종료 상태 회수에 대한 심화 학습을 제공합니다.