ここで使用しているアプリにシグナル ハンドラーを追加しようとしたところ、作成者がsigaction()
他のシグナル ハンドラーを設定するために を使用していたことに気付きました。 を使用するつもりでしたsignal()
。規則に従うには を使用する必要がありますsigaction()
が、最初から作成する場合はどちらを選択すればよいでしょうか。
ベストアンサー1
使用sigaction()
そうしない非常に説得力のある理由がない限りは。
のsignal()
インターフェースは古さ (したがって可用性) という利点があり、C 標準で定義されています。ただし、古い動作を忠実にシミュレートできるようにsigaction()
明示的に追加されたフラグを使用しない限り、回避すべき望ましくない特性がいくつかあります。sigaction()
signal()
- この
signal()
関数は、現在のハンドラの実行中に他のシグナルの到着を(必ずしも)ブロックするわけではありません。sigaction()
現在のハンドラが戻るまで他のシグナルをブロックできます。 - この
signal()
関数は、ほとんどすべてのシグナルのシグナル アクションを (通常)SIG_DFL
デフォルトにリセットします。つまり、signal()
ハンドラーは最初のアクションとして自分自身を再インストールする必要があります。また、シグナルが検出されてからハンドラーが再インストールされるまでの間に脆弱性のウィンドウが開き、その間にシグナルの 2 番目のインスタンスが到着すると、デフォルトの動作 (通常は終了、場合によっては偏見を伴う - コア ダンプとも呼ばれます) が発生します。 - の正確な動作は
signal()
システムによって異なりますが、標準ではそれらの違いが許容されています。
sigaction()
これらは、一般的に の代わりにを使用する十分な理由ですsignal()
。ただし、 のインターフェースはsigaction()
間違いなく扱いにくいです。
どちらを使用する場合でも、次のような代替信号インターフェースに誘惑されないようにしてください。sighold()
、sigignore()
、sigpause()
そしてsigrelse()
これらは名目上は の代替ですsigaction()
が、ほとんど標準化されておらず、本格的な使用ではなく下位互換性のために POSIX に存在しています。POSIX 標準では、マルチスレッド プログラムでのそれらの動作は未定義であるとされていることに注意してください。
マルチスレッド プログラムとシグナルは、まったく別の複雑な話です。
私の知る限り、 と
signal()
は どちらも
sigaction()
マルチスレッド アプリケーションでは問題ありません。
Linuxのマニュアルページ
signal()
言う:
の効果
signal()
マルチスレッド プロセスでは指定されません。
sigaction()
したがって、マルチスレッド プロセスで安全に使用できるのは だけだと思います。
それは興味深いですね。この場合、LinuxのマニュアルページはPOSIXよりも制限が厳しいです。POSIXでは、signal()
:
プロセスがマルチスレッドの場合、またはプロセスがシングルスレッドで、次の結果以外の理由でシグナル ハンドラーが実行された場合:
- プロセスは
abort()
、、、、またはを呼び出してraise()
、ブロックされないシグナルを生成するkill()
pthread_kill()
sigqueue()
- 保留中の信号がブロック解除され、ブロック解除した呼び出しが返される前に配信される
シグナルハンドラが、静的記憶域期間を持つオブジェクト以外を参照する場合、
errno
またはとして宣言されたオブジェクトに値を割り当てる以外の方法で参照する場合volatile sig_atomic_t
、またはシグナルハンドラが、この標準で定義されている関数以外の関数を呼び出す場合、動作は未定義です。信号の概念。
signal()
したがって、POSIX はマルチスレッド アプリケーションにおけるの動作を明確に規定しています。
それでも、sigaction()
基本的にすべての状況で が優先されます。また、移植可能なマルチスレッド コードでsigaction()
は、それができない圧倒的な理由 (「標準 C で定義された関数のみを使用する」など) がない限り、 を使用する必要があります。また、C11 コードはマルチスレッド化できます。これは基本的に、この回答の冒頭の段落でも述べられていることです。