Kill a Child Process em C

Jinku Hu 12 outubro 2023
  1. Use o sinal SIGKILL para encerrar um processo filho em C
  2. Use o sinal SIGTERM para encerrar um processo filho em C
Kill a Child Process em C

Este artigo demonstrará vários métodos sobre como eliminar um processo filho em C.

Use o sinal SIGKILL para encerrar um processo filho em C

Existem vários sinais concebidos para terminar um processo na sua entrega, mas enviar o sinal SIGKILL é o método mais poderoso e seguro para o fazer. Geralmente, um programa pode registrar funções especiais chamadas manipuladores de sinal que são invocados automaticamente assim que o sinal correspondente é entregue ao programa. O usuário implementa o código de função do manipulador que geralmente realiza algum trabalho de limpeza para o programa. Além de manipuladores de função, pode haver ações padrão em sinais entregues, como bloquear e ignorar. Porém, o sinal SIGKILL não pode ser ignorado, bloqueado ou manipulado pela função fornecida. Portanto, este método deve ser o último recurso ao tentar encerrar um processo.

O sinal SIGKILL pode ser enviado com uma chamada de sistema kill. Observe, porém, que o manipulador SIGTERM registrado no exemplo de código a seguir não pode capturar o SIGKILL entregue e imediatamente mata o processo filho fornecido.

O programa a seguir gera um processo filho e registra o manipulador SIGTERM nele. Em seguida, o processo filho executa um loop infinito, a menos que o sinal seja entregue, o que inverte a variável de expressão while. Conseqüentemente, o sinal SIGKILL entregue pelo pai não invoca o manipulador e termina o processo filho instantaneamente.

#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);
}

Use o sinal SIGTERM para encerrar um processo filho em C

Alternativamente, um processo filho pode ser encerrado usando o sinal SIGTERM, que pode ser tratado pelo programa. O próximo exemplo de código repete a implementação do programa anterior, exceto que substitui o sinal SIGKILL por SIGTERM. A função sigfillset é usada para evitar que outros sinais interrompam a execução da função de tratamento registrada. O código do manipulador modifica a variável de tipo global sig_atomic_t que interrompe o loop while no processo filho e imprime o valor da variável count. Porém, lembre-se de que é sempre melhor usar a chamada sigaction acima da função signal ao registrar os manipuladores, já que esta última não é especificada em detalhes pelo padrão 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);
}
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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

Artigo relacionado - C Process