1

シングル スレッド プログラムでは、シグナル ハンドラで競合状態が発生する可能性はありますか?

void signal_handler(...)
{
  static int i = 0;
  i = i + 10 * 10;
}

2 つの非常に近いシグナルがスローされ、それらが同時に関数に入るほど接近していると想像してください。

最近の Linux OS がこれをどのように処理するかについての情報が見つかりません。両方のシグナルが正しく処理されていることはわかっていますが、その方法はわかりません。競合状態は可能ですか?

どんな助けでも感謝します、ありがとう!

4

3 に答える 3

1

追加の重要な注意: 「信頼できるシグナル」(sigaction対応するsa_maskフィールドを持つ POSIX) を使用している場合は、シングルスレッド、シングルプロセスの状況でシグナルがどのように動作するかを制御できます。

上記のようなシグナルハンドラーを持つ単一プロセス P1 の場合を考えてみましょう。シグナルSIGUSR1をキャッチして、それを function に入れたとしますsignal_handler。あなたが の中signal_handlerにいる間に、他のプロセス P2 が別のプロセスSIGUSR1を P1 に送信します (たとえば、 を介して kill)。この信号は、P1 に戻るsa_maskまで(一時的に) 「ブロック」されます。signal_handlerこれは、 にビットを設定しない場合でも当てはまります( に設定しsa_maskない限り、以下を参照してください)。SA_NODEFERsa_flags

SIGUSR2しかし、 functionでキャッチすることも決定したとしますsignal_handler。P2 もSIGUSR2. この場合、SIGUSR2がキャッチされ (またはキャッチされる可能性があります) signal_handler、今度はSIGUSR2シグナルに代わって実行中の別のインスタンスが開始されます。

SIGUSR1whenが処理されていることを確認することで、これを防ぐことができSIGUSR2ます。一時的にもブロックされます。SIGUSR1一般に、処理中はブロックしたいと思うでしょうSIGUSR2。これを行うには、 の対応する両方のビットを設定しますsa_mask

struct sigaction sa;

memset(&sa, 0, sizeof sa);
sa.sa_flags = SA_RESTART | SA_SIGINFO; /* (decide for yourself which flags) */
sigaddset(&sa.sa_mask, SIGUSR1);
sigaddset(&sa.sa_mask, SIGUSR2);
sa.sa_sigaction = signal_handler;
error = sigaction(SIGUSR1, &sa, NULL);
if (error) ... handle error ...
error = sigaction(SIGUSR2, &sa, NULL);
if (error) ... handle error ...

この 2 つのsigaddset呼び出しにより、関数の実行中は SIGUSR1 と SIGUSR2 の両方が保留 (一時的にブロック) されるようになります。

SA_NODEFERシグナルを 1 つだけキャッチする場合、この余分な複雑さは必要ありません。 が設定されていない限り、OS はシグナル ハンドラへのエントリをトリガーしたシグナルを、エントリで設定された「現在ブロックされているシグナル」に自動的に追加するためです。

(シグナルハンドラへの入り口と出口でのシグナルの OS の自動ブロックとブロック解除はsigprocmask、 を使用して、SIG_BLOCKおよびを使用して行われることに注意してください。実際に を呼び出すのではなく、カーネル コード内で実行しますが、効果は同じで、より効率的です)。SIG_SETMASKSIG_UNBLOCKSIG_SETMASKSIG_BLOCKsigprocmask

于 2013-05-29T22:33:09.847 に答える
1

あなたが意味する意味での競合状態はありません(2つのシグナル間)。同じ信号の複数の信号が同時に配信されることはありません。torek の回答で説明されているように、予防策を講じない限り、異なるシグナル番号の複数のシグナルが同時に配信される可能性があります。

静的期間の変数 (またはグローバル変数) を使用する場合は常に、関数は再入可能ではなくなります。これは通常、シグナル ハンドラ関数自体にとっては重要ではありません。ただし、グローバル データまたは静的データにアクセスする他の関数を呼び出すと、その関数は、2 つのスレッドがクリティカル セクションを競合するようなアクセス パターンを確認します。つまり、プログラムは通常の処理を行うためにそのような関数を呼び出していますが、シグナルはその関数の途中で到着し、その後シグナル ハンドラが同じ関数を呼び出します。グローバル/静的変数が一貫性のない状態にある可能性があり、プログラムが非決定的な動作をする可能性があります。

POSIX では、シグナル ハンドラ内から安全に呼び出せる一連の API が定義されています。シグナル ハンドラに実装した関数を呼び出させる場合は、コードで同様の予防措置を講じる必要があります。

于 2013-05-29T20:43:04.033 に答える
1

シングル スレッドとは、一度に 1 つのアプリだけが静的に触れることを意味します。2 つのアプリがある場合、2 つの静的要素があり、競合状態はありません。

これが割り込みハンドラで、i += 100 がアトミックでない場合 (プラットフォーム/CPU に依存する可能性があります)、競合が発生します。

于 2013-05-29T20:25:37.137 に答える