C 언어에서 SIGCHLD로 자식 프로세스 종료 상태 확인하기

C 언어에서 다중 프로세스 환경을 다룰 때, 자식 프로세스의 종료 상태를 올바르게 처리하는 것은 매우 중요합니다. 이를 관리하지 않으면 좀비 프로세스가 발생해 시스템 자원을 낭비하거나 예기치 않은 동작을 유발할 수 있습니다. SIGCHLD 신호는 자식 프로세스의 종료를 감지하고 해당 상태를 처리할 수 있는 유용한 도구입니다. 본 기사에서는 SIGCHLD의 개념과 사용법, 그리고 이를 활용한 프로세스 관리 기법을 자세히 설명합니다.

목차

SIGCHLD 신호란?


SIGCHLD는 POSIX 표준에서 정의된 신호로, 자식 프로세스가 종료되거나 중단될 때 부모 프로세스에 전달됩니다. 이 신호는 부모 프로세스가 자식 프로세스의 종료 상태를 확인하고 이를 적절히 처리할 수 있도록 돕는 역할을 합니다.

SIGCHLD 신호의 목적

  • 좀비 프로세스 방지: 자식 프로세스가 종료된 후 부모 프로세스가 이를 확인하지 않으면 좀비 프로세스가 생성될 수 있습니다. SIGCHLD를 통해 이를 방지할 수 있습니다.
  • 프로세스 상태 관리: 자식 프로세스의 종료, 중단, 재시작 등을 감지하여 시스템 자원을 효과적으로 관리할 수 있습니다.

SIGCHLD 발생 시점

  • 자식 프로세스가 정상적으로 종료될 때
  • 자식 프로세스가 신호에 의해 종료될 때
  • 자식 프로세스가 멈춤 상태로 들어갈 때
  • 자식 프로세스가 다시 실행될 때

SIGCHLD는 부모 프로세스가 비동기적으로 자식 프로세스의 상태 변화를 감지하고, 필요한 작업을 수행할 수 있도록 하는 핵심적인 신호입니다.

자식 프로세스 종료 시그널 처리의 필요성

자식 프로세스 종료 처리를 하지 않을 경우


자식 프로세스가 종료된 후 부모 프로세스가 이를 처리하지 않으면, 운영 체제는 자식 프로세스의 정보를 해제하지 못합니다. 이로 인해 좀비 프로세스가 생성됩니다. 좀비 프로세스는 시스템 메모리를 점유하며, 과도하게 생성될 경우 시스템의 성능에 악영향을 미칠 수 있습니다.

자식 프로세스 종료 처리의 주요 이점

  1. 시스템 자원 해제: 종료된 자식 프로세스의 정보를 운영 체제가 해제하도록 함으로써 메모리와 리소스를 확보할 수 있습니다.
  2. 프로그램 안정성 유지: 모든 자식 프로세스의 종료 상태를 명확히 관리하면 예상치 못한 오류를 방지할 수 있습니다.
  3. 프로세스 동기화: 자식 프로세스의 종료를 확인하고 이에 따라 부모 프로세스가 적절히 동작하도록 보장합니다.

운영 체제와의 관계


운영 체제는 종료된 자식 프로세스의 정보를 프로세스 제어 블록(PCB)에 보관합니다. 부모 프로세스가 이를 회수하지 않으면 좀비 프로세스 상태가 유지됩니다. SIGCHLD 신호를 통해 부모 프로세스가 자식 프로세스의 상태를 확인하고 wait() 함수나 waitpid() 함수를 호출하면, 운영 체제는 자식 프로세스의 PCB를 해제합니다.

적절한 자식 프로세스 종료 처리는 안정적이고 효율적인 시스템 설계를 위해 필수적인 요소입니다.

SIGCHLD 핸들러 설정 방법

SIGCHLD 핸들러의 역할


SIGCHLD 핸들러는 자식 프로세스가 종료되었을 때 이를 감지하고 적절한 작업(예: wait() 호출)을 수행하는 함수입니다. 이를 통해 부모 프로세스는 자식 프로세스 종료 상태를 처리할 수 있습니다.

SIGCHLD 핸들러 작성 예제


아래는 SIGCHLD 신호를 처리하기 위한 기본 핸들러 설정 방법을 보여주는 코드입니다.

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

void sigchld_handler(int sig) {
    int status;
    pid_t pid;

    // 종료된 자식 프로세스 상태 확인
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
        if (WIFEXITED(status)) {
            printf("자식 프로세스 %d 종료, 상태: %d\n", pid, WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("자식 프로세스 %d 신호에 의해 종료, 신호: %d\n", pid, WTERMSIG(status));
        }
    }
}

int main() {
    // SIGCHLD 신호 핸들러 설정
    struct sigaction sa;
    sa.sa_handler = sigchld_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;

    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    // 자식 프로세스 생성
    if (fork() == 0) {
        // 자식 프로세스
        printf("자식 프로세스 실행 중 (PID: %d)\n", getpid());
        sleep(2); // 작업 시뮬레이션
        exit(0);  // 정상 종료
    }

    // 부모 프로세스는 대기
    printf("부모 프로세스 실행 중\n");
    while (1) {
        pause(); // 신호 대기
    }

    return 0;
}

핸들러 설정의 주요 포인트

  1. sigaction 사용: 신호 핸들러를 설정하는 데 sigaction을 사용하면 더 안전하고 유연한 설정이 가능합니다.
  2. SA_NOCLDSTOP 플래그: 자식 프로세스가 멈추었을 때(SIGSTOP)를 무시하고 종료된 경우에만 SIGCHLD를 수신하도록 설정합니다.
  3. WNOHANG 옵션: waitpid 호출에서 블로킹을 방지하여 부모 프로세스가 다른 작업을 수행할 수 있도록 합니다.

핸들러 구현 시 주의 사항

  • 신호 핸들러 내에서 긴 작업을 피해야 하며, 최소한의 작업만 수행해야 합니다.
  • 전역 변수 또는 비동기적으로 안전하지 않은 함수 호출을 주의해야 합니다.

이와 같이 핸들러를 설정하면, 자식 프로세스의 종료 상태를 효과적으로 관리할 수 있습니다.

`wait()` 함수와의 연계

`wait()` 함수란?


wait() 함수는 부모 프로세스가 자식 프로세스의 종료를 기다리도록 하는 시스템 호출입니다. 이 함수는 자식 프로세스가 종료될 때까지 부모 프로세스를 블로킹하며, 종료된 자식 프로세스의 PID와 종료 상태를 반환합니다.

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
  • 매개변수 status: 자식 프로세스의 종료 상태를 저장하는 포인터입니다.
  • 반환값: 종료된 자식 프로세스의 PID를 반환하거나, 오류 시 -1을 반환합니다.

`waitpid()` 함수란?


waitpid()wait()의 확장형으로, 특정 자식 프로세스를 기다리거나 비블로킹 방식으로 호출할 수 있습니다.

#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
  • pid: 기다릴 자식 프로세스의 PID 또는 특별 플래그(-1 등)를 지정합니다.
  • options: 비블로킹 호출을 위한 WNOHANG 플래그를 포함할 수 있습니다.

예제 코드: `wait()`와 `waitpid()` 사용

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

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

    if (pid == 0) {
        // 자식 프로세스
        printf("자식 프로세스 실행 중 (PID: %d)\n", getpid());
        sleep(2);
        exit(42);  // 종료 코드 42
    } else if (pid > 0) {
        // 부모 프로세스
        int status;
        pid_t child_pid = wait(&status);  // 자식 프로세스 종료 대기
        if (child_pid == -1) {
            perror("wait");
            exit(1);
        }
        if (WIFEXITED(status)) {
            printf("자식 프로세스 %d 종료, 상태: %d\n", child_pid, WEXITSTATUS(status));
        }
    } else {
        perror("fork");
        exit(1);
    }

    return 0;
}

`wait()`와 `SIGCHLD`의 연계


SIGCHLD 핸들러에서 wait() 또는 waitpid()를 호출하여 자식 프로세스의 종료 상태를 확인할 수 있습니다. 핸들러와 연계하면 부모 프로세스가 자식 프로세스 종료를 비동기적으로 처리할 수 있습니다.

예제

void sigchld_handler(int sig) {
    int status;
    pid_t pid;

    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
        if (WIFEXITED(status)) {
            printf("자식 프로세스 %d 종료, 상태: %d\n", pid, WEXITSTATUS(status));
        }
    }
}

`wait()` 및 `waitpid()` 사용 시 주의 사항

  1. 좀비 프로세스 방지: 반드시 wait() 또는 waitpid()를 호출하여 종료된 자식 프로세스를 회수해야 합니다.
  2. 비블로킹 처리: WNOHANG 옵션을 사용하면 부모 프로세스의 작업 흐름을 중단하지 않고 자식 프로세스를 관리할 수 있습니다.
  3. 여러 자식 프로세스: 여러 자식 프로세스를 관리할 때는 waitpid(-1, ...)를 반복 호출하여 모든 종료 상태를 확인해야 합니다.

이러한 방식으로 wait()SIGCHLD를 결합하면 자식 프로세스의 종료를 효과적으로 관리할 수 있습니다.

여러 자식 프로세스 관리

여러 자식 프로세스와 SIGCHLD


동시에 여러 자식 프로세스를 실행할 때, SIGCHLD 신호와 waitpid()를 활용하면 각 프로세스의 종료 상태를 효율적으로 관리할 수 있습니다. 특히 동적 프로세스 관리가 필요한 서버나 병렬 작업을 수행하는 프로그램에서 유용합니다.

동시에 여러 자식 프로세스 생성하기


여러 자식 프로세스를 생성하고 관리하는 기본 예제입니다.

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

void sigchld_handler(int sig) {
    int status;
    pid_t pid;

    // 종료된 모든 자식 프로세스 상태 처리
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
        if (WIFEXITED(status)) {
            printf("자식 프로세스 %d 종료, 상태: %d\n", pid, WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("자식 프로세스 %d 신호에 의해 종료, 신호: %d\n", pid, WTERMSIG(status));
        }
    }
}

int main() {
    struct sigaction sa;
    sa.sa_handler = sigchld_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    // 여러 자식 프로세스 생성
    for (int i = 0; i < 3; i++) {
        pid_t pid = fork();
        if (pid == 0) {
            // 자식 프로세스
            printf("자식 프로세스 실행 중 (PID: %d)\n", getpid());
            sleep(i + 1);  // 각 프로세스의 작업 시간
            exit(i + 10);  // 종료 코드
        } else if (pid < 0) {
            perror("fork");
            exit(1);
        }
    }

    // 부모 프로세스는 대기
    printf("부모 프로세스 실행 중\n");
    while (1) {
        pause();  // 신호 대기
    }

    return 0;
}

여러 프로세스 상태 관리 전략

  1. PID로 특정 프로세스 추적
    waitpid()에 자식 프로세스의 PID를 명시적으로 전달하여 특정 프로세스의 종료 상태를 추적합니다.
  2. 비블로킹 방식으로 모든 프로세스 확인
    SIGCHLD 신호와 WNOHANG 옵션을 결합하여 종료된 모든 자식 프로세스를 반복적으로 처리합니다.
  3. 상태별 로깅
    각 자식 프로세스의 종료 상태를 로깅하거나 추적하기 위해 해시맵 또는 배열을 활용합니다.

예: 자식 프로세스 추적

int child_pids[3];  // 자식 PID 저장용 배열

for (int i = 0; i < 3; i++) {
    pid_t pid = fork();
    if (pid == 0) {
        // 자식 프로세스
        sleep(i + 1);
        exit(0);
    } else if (pid > 0) {
        child_pids[i] = pid;  // PID 저장
    }
}

// 특정 PID 추적
for (int i = 0; i < 3; i++) {
    waitpid(child_pids[i], NULL, 0);  // 각 자식 프로세스 대기
}

주의 사항

  • 동기화 문제: 자식 프로세스 종료를 효율적으로 처리하려면 SIGCHLD 핸들러와 부모 프로세스의 작업이 겹치지 않도록 주의해야 합니다.
  • 리소스 누수 방지: 모든 자식 프로세스를 명확히 회수(wait() 또는 waitpid())해야 리소스 누수를 방지할 수 있습니다.
  • PID 충돌 관리: PID를 추적할 경우, 같은 PID가 재사용되는 상황을 대비해 추가 상태 검사를 수행하는 것이 좋습니다.

SIGCHLD와 waitpid()를 활용하면 여러 자식 프로세스를 동적으로 관리할 수 있으며, 이를 통해 프로세스 기반 병렬 작업을 효율적으로 구현할 수 있습니다.

응용: SIGCHLD를 활용한 비동기 작업

SIGCHLD를 비동기 작업에 활용하는 이유


SIGCHLD는 자식 프로세스의 종료를 감지하여 부모 프로세스가 중단되지 않고 비동기적으로 작업을 처리할 수 있도록 돕습니다. 이를 활용하면, 부모 프로세스는 다른 작업을 수행하는 동안 자식 프로세스의 종료를 효율적으로 관리할 수 있습니다.

예제: SIGCHLD를 활용한 비동기 작업 처리


다음 예제는 여러 자식 프로세스에서 병렬로 작업을 수행하고, 종료 상태를 비동기적으로 처리하는 프로그램입니다.

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

void sigchld_handler(int sig) {
    int status;
    pid_t pid;

    // 종료된 모든 자식 프로세스 상태 확인
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
        if (WIFEXITED(status)) {
            printf("자식 프로세스 %d 완료, 종료 코드: %d\n", pid, WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("자식 프로세스 %d 신호에 의해 종료, 신호: %d\n", pid, WTERMSIG(status));
        }
    }
}

int main() {
    struct sigaction sa;
    sa.sa_handler = sigchld_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;

    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    // 병렬 작업 수행을 위한 여러 자식 프로세스 생성
    for (int i = 0; i < 3; i++) {
        pid_t pid = fork();
        if (pid == 0) {
            // 자식 프로세스: 작업 시뮬레이션
            printf("자식 프로세스 %d 실행 중\n", getpid());
            sleep(i + 2);  // 각기 다른 시간 동안 작업 수행
            exit(i + 1);   // 종료 코드 반환
        } else if (pid < 0) {
            perror("fork");
            exit(1);
        }
    }

    // 부모 프로세스는 다른 작업 수행
    printf("부모 프로세스: 자식 작업을 비동기적으로 모니터링 중\n");
    while (1) {
        pause();  // 신호 대기
    }

    return 0;
}

코드 설명

  1. 자식 프로세스 병렬 생성
  • 부모 프로세스는 fork()를 사용해 여러 자식 프로세스를 병렬로 실행합니다.
  1. SIGCHLD 핸들러
  • 자식 프로세스 종료 시 SIGCHLD 신호가 발생하며, 핸들러에서 비동기적으로 상태를 확인합니다.
  1. 작업 중단 없이 진행
  • 부모 프로세스는 pause()를 호출하여 SIGCHLD 신호를 대기하거나 다른 작업을 병행할 수 있습니다.

비동기 작업의 장점

  • 병렬 처리: 자식 프로세스는 서로 독립적으로 작업을 수행하므로 전체 처리 속도를 높일 수 있습니다.
  • 자원 관리 효율성: 부모 프로세스는 SIGCHLD 신호와 waitpid()를 통해 리소스를 효율적으로 회수합니다.
  • 응답성 유지: 부모 프로세스는 다른 작업을 수행하며 대기 상태를 유지할 수 있습니다.

응용 사례

  1. 병렬 데이터 처리: 데이터를 여러 작업으로 나누어 병렬 처리 후 결과를 통합.
  2. 서버 프로세스 관리: 클라이언트 요청을 처리하는 여러 프로세스를 관리하며, 종료된 프로세스의 자원을 회수.
  3. 작업 큐 실행: 큐에 등록된 작업을 병렬로 실행하며 각 작업 종료 상태를 모니터링.

SIGCHLD를 활용한 비동기 작업은 효율적인 프로세스 관리를 가능하게 하며, 병렬 처리의 장점을 극대화합니다.

트러블슈팅: SIGCHLD 핸들링 관련 문제 해결

문제 1: 좀비 프로세스가 계속 발생


현상: 자식 프로세스가 종료되었지만 부모 프로세스가 이를 적절히 처리하지 않아 좀비 프로세스가 생성됨.
원인: SIGCHLD 신호를 처리하지 않거나, wait() 또는 waitpid()를 호출하지 않아 종료된 자식 프로세스의 상태 정보가 해제되지 않음.

해결 방법:

  1. SIGCHLD 핸들러를 설정하여 종료된 자식 프로세스를 회수.
  2. 부모 프로세스가 자식 프로세스 종료를 처리할 수 있도록 waitpid()를 사용.

코드 수정 예제:

void sigchld_handler(int sig) {
    while (waitpid(-1, NULL, WNOHANG) > 0);
}

문제 2: SIGCHLD 신호가 누락됨


현상: 자식 프로세스가 종료되었지만 SIGCHLD 신호가 발생하지 않거나 부모 프로세스가 이를 수신하지 못함.
원인:

  • sigaction 또는 signal() 함수가 제대로 설정되지 않음.
  • SA_NOCLDSTOP 플래그가 누락되어 자식 프로세스의 멈춤 상태에서 불필요한 신호가 발생.

해결 방법:

  1. sigaction을 올바르게 설정하고, SA_NOCLDSTOP 및 SA_RESTART 플래그를 추가.
  2. 핸들러를 재설정하여 SIGCHLD 신호를 명확히 처리.

코드 수정 예제:

struct sigaction sa;
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
    perror("sigaction");
    exit(1);
}

문제 3: SIGCHLD 핸들러에서의 블로킹


현상: SIGCHLD 핸들러 내부에서 블로킹 작업이 수행되어 시스템 응답 속도가 느려짐.
원인: 신호 핸들러에서 블로킹 함수(wait() 등)를 사용하거나, 긴 작업을 수행.

해결 방법:

  1. 신호 핸들러 내부에서 waitpid()를 비블로킹 모드(WNOHANG)로 호출.
  2. 긴 작업은 핸들러 외부의 메인 루프에서 수행하도록 설계.

코드 수정 예제:

void sigchld_handler(int sig) {
    int status;
    while (waitpid(-1, &status, WNOHANG) > 0) {
        // 간단한 로그 출력만 수행
        if (WIFEXITED(status)) {
            printf("자식 프로세스 종료\n");
        }
    }
}

문제 4: 부모 프로세스의 멈춤


현상: 부모 프로세스가 자식 프로세스를 처리하는 동안 멈추거나 응답하지 않음.
원인:

  • 신호 핸들링 외의 작업에서 블로킹 함수 사용.
  • 적절한 비동기 작업 관리가 이루어지지 않음.

해결 방법:

  1. pause() 대신 비블로킹 루프를 사용하여 신호와 다른 작업을 병행.
  2. 신호 처리를 최소화하고, 비동기 작업 설계.

코드 수정 예제:

while (1) {
    // 다른 작업 수행
    printf("부모 프로세스 작업 중...\n");
    sleep(1);
}

문제 5: 부모 프로세스에서의 `wait()` 호출 실패


현상: wait() 또는 waitpid() 호출 시 -1 반환과 함께 ECHILD 오류 발생.
원인: 부모 프로세스에 남아 있는 자식 프로세스가 없음.

해결 방법:

  • waitpid()를 호출할 때 자식 프로세스의 존재 여부를 확인하도록 설계.
  • 필요 시 SIGCHLD 신호 핸들러에서만 waitpid()를 호출.

코드 수정 예제:

pid_t pid = waitpid(-1, NULL, WNOHANG);
if (pid == -1 && errno != ECHILD) {
    perror("waitpid");
}

결론


SIGCHLD 핸들링에서 발생하는 주요 문제는 올바른 신호 처리 및 waitpid() 사용으로 해결할 수 있습니다. 비동기 작업을 적절히 설계하고, 시스템 호출의 동작 원리를 이해하면 안정적이고 효율적인 프로세스 관리를 구현할 수 있습니다.

실습: SIGCHLD를 활용한 프로세스 모니터링 구현

실습 목표

  • SIGCHLD 신호를 활용하여 자식 프로세스의 상태를 실시간으로 모니터링합니다.
  • 여러 자식 프로세스를 병렬로 실행하고, 각 프로세스의 종료 상태를 기록합니다.
  • 부모 프로세스는 자식 프로세스 종료 시점에서 상태를 처리합니다.

예제 코드: 프로세스 모니터링

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

void sigchld_handler(int sig) {
    int status;
    pid_t pid;

    // 종료된 자식 프로세스의 상태를 처리
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
        if (WIFEXITED(status)) {
            printf("[모니터] 자식 프로세스 %d 종료 (종료 코드: %d)\n", pid, WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("[모니터] 자식 프로세스 %d 강제 종료 (신호: %d)\n", pid, WTERMSIG(status));
        }
    }
}

int main() {
    struct sigaction sa;
    sa.sa_handler = sigchld_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;

    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    // 여러 자식 프로세스 생성
    for (int i = 0; i < 5; i++) {
        pid_t pid = fork();
        if (pid == 0) {
            // 자식 프로세스
            printf("[자식] 프로세스 %d 작업 시작\n", getpid());
            sleep(i + 1);  // 각기 다른 시간 동안 작업
            printf("[자식] 프로세스 %d 작업 완료\n", getpid());
            exit(i);  // 종료 코드로 작업 번호 반환
        } else if (pid < 0) {
            perror("fork");
            exit(1);
        }
    }

    // 부모 프로세스는 신호를 기다리며 작업 수행
    printf("[부모] 프로세스 모니터링 중...\n");
    while (1) {
        pause();  // SIGCHLD 신호를 대기
    }

    return 0;
}

코드 설명

  1. SIGCHLD 핸들러 등록
  • sigaction을 사용해 SIGCHLD 신호가 발생할 때 호출될 핸들러를 등록합니다.
  • 핸들러 내부에서 waitpid()로 자식 프로세스 상태를 확인하고 로그를 출력합니다.
  1. 여러 자식 프로세스 생성
  • 부모 프로세스는 fork()를 사용해 5개의 자식 프로세스를 생성합니다.
  • 각 자식 프로세스는 독립적으로 작업을 수행한 후 종료합니다.
  1. 비동기 신호 처리
  • 부모 프로세스는 SIGCHLD 신호가 발생할 때만 핸들러를 호출하며, 대기 상태를 유지합니다.
  • 핸들러는 비블로킹 방식으로 자식 프로세스의 종료 상태를 처리합니다.

실행 결과


실행하면 자식 프로세스가 작업을 마칠 때마다 부모 프로세스가 종료 상태를 출력합니다.

[부모] 프로세스 모니터링 중...
[자식] 프로세스 12345 작업 시작
[자식] 프로세스 12346 작업 시작
[자식] 프로세스 12347 작업 시작
[자식] 프로세스 12348 작업 시작
[자식] 프로세스 12349 작업 시작
[자식] 프로세스 12345 작업 완료
[모니터] 자식 프로세스 12345 종료 (종료 코드: 0)
[자식] 프로세스 12346 작업 완료
[모니터] 자식 프로세스 12346 종료 (종료 코드: 1)
[자식] 프로세스 12347 작업 완료
[모니터] 자식 프로세스 12347 종료 (종료 코드: 2)
...

실습 요점

  • SIGCHLD 신호와 waitpid()를 활용하면 자식 프로세스의 종료를 비동기적으로 처리할 수 있습니다.
  • 이 코드는 다중 프로세스 환경에서 자식 프로세스의 상태를 실시간으로 모니터링하고 관리하는 데 유용합니다.
  • 부모 프로세스는 다른 작업을 수행하거나 유휴 상태로 대기하며 효율적으로 자식 프로세스를 관리할 수 있습니다.

요약


본 기사에서는 C 언어에서 SIGCHLD 신호를 활용하여 자식 프로세스의 종료 상태를 감지하고 처리하는 방법을 다뤘습니다. SIGCHLD의 개념, 핸들러 설정, wait()waitpid() 함수와의 연계, 여러 자식 프로세스 관리, 비동기 작업 구현, 그리고 SIGCHLD 핸들링에서 발생하는 문제와 해결 방법을 포함해 실습 예제까지 상세히 설명했습니다. 이를 통해 다중 프로세스 환경에서 자식 프로세스를 효과적으로 관리하고 시스템 자원을 최적화할 수 있는 방법을 이해할 수 있습니다.

목차