C에서 자식 프로세스 죽이기
이 기사는 C에서 자식 프로세스를 종료하는 방법에 대한 여러 가지 방법을 보여줍니다.
SIGKILL
신호를 사용하여 C에서 하위 프로세스 종료
전달시 프로세스를 종료하도록 설계된 여러 신호가 있지만SIGKILL
신호를 보내는 것이 가장 강력하고 확실한 방법입니다. 일반적으로 프로그램은 해당 신호가 프로그램에 전달되면 자동으로 호출되는 신호 핸들러라는 특수 함수를 등록 할 수 있습니다. 사용자는 일반적으로 프로그램에 대한 일부 정리 작업을 수행하는 핸들러 함수 코드를 구현합니다. 함수 핸들러 외에도 차단 및 무시와 같은 전달 된 신호에 대한 기본 작업이있을 수 있습니다. 그러나SIGKILL
신호는 주어진 함수에 의해 무시, 차단 또는 처리 될 수 없습니다. 따라서이 방법은 프로세스를 종료 할 때 최후의 수단이되어야합니다.
SIGKILL
신호는kill
시스템 호출로 전송 될 수 있습니다. 그러나 다음 코드 샘플에 등록 된SIGTERM
핸들러는 전달 된SIGKILL
을 포착 할 수 없으며 주어진 하위 프로세스를 즉시 종료합니다.
다음 프로그램은 자식 프로세스를 생성하고 그 안에SIGTERM
핸들러를 등록합니다. 그런 다음 하위 프로세스는 신호가 전달되지 않는 한 무한 루프를 실행하여while
표현식 변수를 뒤집습니다. 결과적으로 부모가 전달한SIGKILL
신호는 핸들러를 호출하지 않고 자식 프로세스를 즉시 종료합니다.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
volatile sig_atomic_t shutdown_flag = 1;
void cleanupRoutine(int signal_number) { shutdown_flag = 0; }
int main(void) {
int wstatus;
pid_t c_pid = fork();
if (c_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (c_pid == 0) {
printf("printed from child process - %d\n", getpid());
int count = 0;
struct sigaction sigterm_action;
memset(&sigterm_action, 0, sizeof(sigterm_action));
sigterm_action.sa_handler = &cleanupRoutine;
sigterm_action.sa_flags = 0;
// Mask other signals from interrupting SIGTERM handler
if (sigfillset(&sigterm_action.sa_mask) != 0) {
perror("sigfillset");
exit(EXIT_FAILURE);
}
// Register SIGTERM handler
if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) {
perror("sigaction SIGTERM");
exit(EXIT_FAILURE);
}
while (shutdown_flag) {
count += 1;
}
printf("count = %d\n", count);
exit(EXIT_SUCCESS);
} else {
printf("printed from parent process - %d\n", getpid());
int ret;
sleep(5);
ret = kill(c_pid, SIGKILL);
if (ret == -1) {
perror("kill");
exit(EXIT_FAILURE);
}
if (waitpid(c_pid, &wstatus, WUNTRACED | WCONTINUED) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}
SIGTERM
신호를 사용하여 C에서 하위 프로세스 종료
또는 프로그램에서 처리 할 수있는SIGTERM
신호를 사용하여 하위 프로세스를 종료 할 수 있습니다. 다음 코드 샘플은SIGKILL
신호를SIGTERM
으로 대체한다는 점을 제외하고 이전 프로그램 구현을 반복합니다. sigfillset
함수는 다른 신호가 등록 된 핸들러 함수 실행을 방해하는 것을 방지하는 데 사용됩니다. 핸들러 코드는 하위 프로세스에서while
루프를 중지하고count
변수의 값을 인쇄하는 전역sig_atomic_t
유형 변수를 수정합니다. 하지만 핸들러를 등록 할 때signal
함수 위에sigaction
호출을 사용하는 것이 항상 더 좋습니다. 후자는 POSIX 표준에 의해 자세히 지정되어 있지 않기 때문입니다.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
volatile sig_atomic_t shutdown_flag = 1;
void cleanupRoutine(int signal_number) { shutdown_flag = 0; }
int main(void) {
int wstatus;
pid_t c_pid = fork();
if (c_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (c_pid == 0) {
printf("printed from child process - %d\n", getpid());
int count = 0;
struct sigaction sigterm_action;
memset(&sigterm_action, 0, sizeof(sigterm_action));
sigterm_action.sa_handler = &cleanupRoutine;
sigterm_action.sa_flags = 0;
// Mask other signals from interrupting SIGTERM handler
if (sigfillset(&sigterm_action.sa_mask) != 0) {
perror("sigfillset");
exit(EXIT_FAILURE);
}
// Register SIGTERM handler
if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) {
perror("sigaction SIGTERM");
exit(EXIT_FAILURE);
}
while (shutdown_flag) {
count += 1;
}
printf("count = %d\n", count);
exit(EXIT_SUCCESS);
} else {
printf("printed from parent process - %d\n", getpid());
int ret;
sleep(5);
ret = kill(c_pid, SIGTERM);
if (ret == -1) {
perror("kill");
exit(EXIT_FAILURE);
}
if (waitpid(c_pid, &wstatus, WUNTRACED | WCONTINUED) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook