2016-11-10 1 views
2

ここにはvolatile sig_atomic_tを使用する簡単なおもちゃプログラムがあります。シグナルハンドリングのコンテキストで、どの変数が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を変更するループが見つからないため、quitは常に0のままであるとみなします。
  2. quitへの更新またはquitの読み取りは、1回のマシン命令で実行する必要があります。 quitを更新または読み取るために複数のマシン命令が必要な場合、更新中にシグナルハンドラが呼び出された場合、シグナルハンドラの読み込みには一貫性のない値がquitになることがあります。

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

信号処理のコンテキストでsig_atomic_tが必要な場合の一般化されたルールを学びたいと思います。 Jonathan Lefflerはこのコメントで、一般化を提供することは容易ではないと説明した。

変数をC標準の観点からsig_atomic_tと定義する必要がある既知のシナリオのリストを提供できますか?網羅的なリストである必要はありません。あまり経験の浅い開発者が参照することができるリストで、C言語のソフトウェアに信号処理コードを記述することができます。

+0

'一般化'は容易ではありません。シグナルハンドリングのセマンティクスは、異なるマシンでは異なります。 C標準は、シグナルハンドラでできることを信じられないほど制限しています。 POSIXはもっと寛大ですが、依然として厳しい制限があります(例えば、 'strlen()'は安全に使うことはできませんが、 'write()'はできます)。 Windowsのルールはおそらくもう一度異なっています。 'sigaction()'や 'signal()'や他のAPIを使う予定ですか?ポイント(1)に関して、「はい」。ポイント(2) "多かれ少なかれ"(問題のない程度に近い)。 –

+0

@JonathanLefflerコメントありがとうございます。私は質問の範囲を絞り込んだ:(1)変数が 'sig_atomic_t'として定義される必要がある既知のシナリオのリストを要求する(完全なリストである必要はない)(2)良い答えを求めるC標準(POSIXではなく)用です。 –

答えて

1

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

c99 specから2つの関連するセクションがある:

(§7.14P2)
[sig_atomic_tタイプ]はアクセスすることができるオブジェクトの(おそらくは揮発性修飾)整数型であります信号がabortまたはの呼び出しの結果として以外発生した場合であっても、非同期の存在下で原子エンティティは、

(§7.14.1.1のP5)
を遮断するように信号ハンドラは、volatile sig_atomic_tとして宣言されたオブジェクトに値を割り当てることによってより他の静的記憶期間で任意のオブジェクトを参照する場合機能は、動作は

「静的記憶期間」として定義され...未定義です。

(§6.2.4のP3)
識別子、またはストレージ・クラス指定staticと外部または内部リンケージで宣言され静的記憶域期間を持つオブジェクト。その寿命はプログラムの実行全体であり、その格納された値はプログラムの起動前に一度だけ初期化されます。一言で言えば

、あなたは、変数(すなわち、変数は内部及びシグナルハンドラの内外アクセスされる)非同期にアクセスすることができる場合volatile sig_atomic_tを使用する必要があります。さらに、静的記憶期間を有する変数volatile sig_atomic_tにアクセスすることは未定義の動作である。未定義の動作とは、変数の値が矛盾するだけでなく、プログラムが完全に(segfaultのように)何か他のことを行う可能性があることを意味します。

関連する問題