1. ホーム
  2. c

[解決済み] シグナルハンドラでprintfを使用しないようにするには?

2023-02-24 20:20:15

質問

以下 printf はリエントラントではないので、シグナルハンドラで使うのは安全でないはずです。しかし、私は多くのサンプルコードで printf をこのように使っているコード例をたくさん見ました。

そこで質問ですが、どのような場合に printf の使用を避ける必要があるのはどのような場合か、また、推奨される代替手段はあるか?

どのように解決するのですか?

フラグ変数を使用して、シグナルハンドラ内でそのフラグを設定し、そのフラグに基づき printf() 関数を呼び出すことができます。

<ブロッククオート

などのすべての関数を呼び出すことは安全ではありません。 printf のようなすべての関数をシグナルハンドラ内から呼び出すことは安全ではありません。 便利なテクニックは、シグナルハンドラで flag を設定し、次にその flag をチェックし、必要ならメッセージを表示します。

以下の例では、シグナルハンドラ ding() がフラグをセットしていることに注意してください。 alarm_fired を 1 に設定し、メイン関数で alarm_fired の値が調べられ、条件付きで正しくprintfが呼び出されます。

static int alarm_fired = 0;
void ding(int sig) // can be called asynchronously
{
  alarm_fired = 1; // set flag
}
int main()
{
    pid_t pid;
    printf("alarm application starting\n");
    pid = fork();
    switch(pid) {
        case -1:
            /* Failure */
            perror("fork failed");
            exit(1);
        case 0:
            /* child */
            sleep(5);
            kill(getppid(), SIGALRM);
            exit(0);
    }
    /* if we get here we are the parent process */
    printf("waiting for alarm to go off\n");
    (void) signal(SIGALRM, ding);
    pause();
    if (alarm_fired)  // check flag to call printf
      printf("Ding!\n");
    printf("done\n");
    exit(0);
}

<サブ 参照 はじめてのLinuxプログラミング 第4版 この本では、まさにあなたのコードが説明されています(あなたが望むもの)、第11章:プロセスとシグナル、ページ484 の

さらに、ハンドラ関数は非同期に呼び出される可能性があるため、ハンドラ関数を書く際には特別な注意を払う必要があります。つまり、ハンドラはプログラムのどの時点でも、予測不可能に呼び出される可能性があるのです。もし、2つのシグナルが非常に短い間隔で到着した場合、1つのハンドラが別のハンドラの中で実行される可能性があります。そして、より良いプラクティスと考えられているのが volatile sigatomic_t このタイプは常にアトミックにアクセスされ、変数へのアクセスの中断に関する不確実性を避けることができます。(読む アトミックデータアクセスとシグナルハンドリング を参照してください)。

読む シグナルハンドラの定義 を読んでください。 signal() または sigaction() のような関数があります。

で許可された関数のリスト マニュアルページ この関数は、シグナルハンドラ内で呼び出しても問題ありません。