C 言語で子プロセスを強制終了する

胡金庫 2023年10月12日
  1. C 言語で SIGKILL シグナルを使用して子プロセスを終了する
  2. C 言語で SIGTERM シグナルを使用して子プロセスを終了する
C 言語で子プロセスを強制終了する

この記事では、C 言語で子プロセスを強制終了する方法に関する複数の方法を示します。

C 言語で SIGKILL シグナルを使用して子プロセスを終了する

配信時にプロセスを終了するように設計された複数のシグナルがありますが、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);
}

C 言語で SIGTERM シグナルを使用して子プロセスを終了する

または、プログラムで処理できる 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);
}
著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

DelftStack.comの創設者です。Jinku はロボティクスと自動車産業で8年以上働いています。自動テスト、リモートサーバーからのデータ収集、耐久テストからのレポート作成が必要となったとき、彼はコーディングスキルを磨きました。彼は電気/電子工学のバックグラウンドを持っていますが、組み込みエレクトロニクス、組み込みプログラミング、フロントエンド/バックエンドプログラミングへの関心を広げています。

LinkedIn Facebook

関連記事 - C Process