3

を使用した簡単なおもちゃのプログラムを次に示しますvolatile sig_atomic_t

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

#define UNUSED(x) (void) (x)

volatile sig_atomic_t quit;

void sigusr1_handler(int sig)
{
    UNUSED(sig);
    write(1, "handler\n", 8);
    quit = 1;
}

int main()
{
    struct sigaction sa;

    sa.sa_handler = sigusr1_handler;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);

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

    quit = 0;
    while (!quit)
        ;

    printf("Exiting ...\n");
    return 0;
}

この特定のプログラムの変数にvolatile sig_atomic_t必要な理由はわかっていると思います。quit

  1. がないvolatileと、コンパイラはwhile (!quit) ;無限ループに最適化する可能性があります。ループの変更が見つからないため、常に残っquitていると見なされます。quit0
  2. への更新quitまたは読み取りはquit、単一のマシン命令で発生する必要があります。の更新または読み取りに複数のマシン命令が必要quitな場合、更新の進行中にシグナル ハンドラーが呼び出されると、シグナル ハンドラーの読み取りで の値が矛盾する可能性がありますquit

私はこれまでのところ正しいですか?そうでない場合は、答えを修正してください。

sig_atomic_tここで、シグナル処理のコンテキストで必要な場合の一般化されたルールを学びたいと思います。Jonathan Leffler はコメントで、一般化するのは簡単ではないと説明しました。

sig_atomic_tC標準の観点から、変数を定義する必要がある既知のシナリオのリストを提供できますか? 網羅的なリストである必要はありません。これは、経験の浅い開発者がシグナル処理コードを含む C ソフトウェアを作成する際に参照できるリストになる可能性があります。

4

1 に答える 1

3

sig_atomic_tC標準の観点から、変数を定義する必要がある既知のシナリオのリストを提供できますか?

c99 仕様から 2 つの関連セクションがあります。

(§7.14 p2)
[sig_atomic_t型] は、非同期割り込みが存在する場合でも、アトミック エンティティとしてアクセスできるオブジェクトの (おそらく volatile 修飾された) 整数型です。

(§7.14.1.1 p5) or関数
の呼び出しの結果以外でシグナルが発生した場合、シグナル ハンドラーが、 として宣言されたオブジェクトに値を代入する以外の方法で静的ストレージ期間を持つオブジェクトを参照する場合、動作は未定義です。 ...abortraisevolatile sig_atomic_t

「静的保存期間」は次のように定義されます。

(§6.2.4 p3)
識別子が外部リンケージまたは内部リンケージ、またはストレージ クラス指定子で宣言されているオブジェクトには、static静的ストレージ期間があります。その存続期間はプログラムの実行全体であり、格納された値はプログラムの起動前に一度だけ初期化されます。

volatile sig_atomic_t簡単に言えば、変数が非同期でアクセスできる場合 (つまり、変数がシグナル ハンドラの内部と外部の両方でアクセスされる場合)に使用する必要があります。さらに、volatile sig_atomic_t静的な保存期間を持つ非変数にアクセスすることは、未定義の動作です。未定義の動作とは、変数の値が矛盾する可能性があるだけでなく、プログラムがまったく別のこと (segfault など) を実行できることを意味します。

于 2016-11-11T02:35:42.237 に答える