3

私は現在、コードの重要なセグメントが実行されているときにsigprocmask特定のシグナル (この場合はSIGALRMと) をブロックするために を使用することを研究しています。SIGCHLDこれらのシグナルに関連付けられた両方のシグナル ハンドラーは、中央のデータ構造にアクセスして変更するため、メイン プロセスが処理している間は、これらのシグナル ハンドラーがデータ構造にアクセスできないようにすることが重要です。

現時点では、コードのクリティカル セクションの開始時にこれらのシグナルを単純に無効にし、最後に再度有効にする予定です。

void criticalFunction(void) {
    // disable signals with sigprocmask
    // critical code
    // enable signals with sigprocmask
}

ただし、ブロックされるシグナルのシグナルハンドラも を呼び出しますcriticalFunctionsigprocmask関数を呼び出して独自のシグナルでブロッキングを有効にするとどうなるでしょうか? それらは停止しますか、それとも実行を続けますか? (またはいくつかの 3 番目の条件..)

これについて私が見つけることができた唯一のメモは次のとおりです。

sigprocmask() がシグナルハンドラーで呼び出された場合、ハンドラーから戻ると、元の保留中のシグナルマスクを復元することにより、sigprocmask() の作業が取り消される場合があります。( http://www.mkssoftware.com/docs/man3/sigprocmask.3.asp )

(これは私の前の質問へのフォローアップの質問です:キューのデータ構造にアクセスするシグナルハンドラー (競合状態?) )

4

2 に答える 2

4

シグナルハンドラー内のデフォルトの動作は、処理中のシグナルをブロックすることであることに注意してください。また、シグナル ハンドラー内で関数呼び出しを行う場合は、シグナル セーフな関数のみを呼び出します。そうは言っても、sigprocmask()シグナルセーフ関数であり、シグナルハンドラーによってブロックされている同じシグナルをブロックするためにそれを使用している場合、内部で呼び出されている場合、実際には何も起こりません...あなたはするつもりです現在持っているのと同じシグナル マスクのままにします。唯一の違いは、シグナル ハンドラー内では、 または のいずれかのシグナルのみSIGALRMSIGCHLDブロックされることが保証されていることです (どちらのシグナル ハンドラーにいるかによって異なります)。sigprocmask()これらの特定のシグナルをブロックするために呼び出すと、両方のシグナル通話後にブロックされます。

注意すべきことは、シグナルマスクで現在ブロックされているシグナルを有効criticalFunctionにするために呼び出しsigprocmask()を試みるときのコードの 2 番目の部分です。これにより、シグナル ハンドラーへの呼び出しで一定レベルの再入可能性が発生する状況が発生する可能性があります。言い換えれば、現在のシグナルハンドラーのシグナルを有効にするということは、現在のシグナルハンドラーを終了する前に、別のorがキャッチされ、シグナルハンドラーに再び入り、この新しくキャッチされたシグナルを処理することを意味します。 . クリティカルセクションの更新後にシグナルを有効にしている限り、この再入可能な状況で問題ないと思いますが、安全を期すために、最後にのみシグナルを有効にすることをお勧めしますのSIGALRMSIGCHLDcriticalFunctioncriticalFunction、途中のどこかではなく、から戻ったときに、criticalFunction非同期セーフではないことは何もしないでください... 2番目の戻り後のコードは、sigprocmask()順番どおりに実行されていない可能性があると想定する必要があります(つまり、2 番目のシグナルがキャッチされ、そのシグナルハンドラーが実行された後に実行されている可能性があります)。

exec家族から何かを呼び出そうとした場合、またはシグナルハンドラー内でその性質のものを呼び出そうとした場合にのみ、「ストール」について心配する必要があります。新しくオーバーレイされたプロセスは現在のプロセスからシグナルマスクを継承するため、現在のプロセスが特定のシグナルをブロックしていた場合、それらは新しいプロセスでもブロックされます。したがって、新しいプロセスがシグナルがブロックされていないと想定していた場合、新しいプロセスのシグナルハンドラーは決して実行されません。

ところで、1 つの警告:シグナルとスレッドを混在させないでください。質問で「メインプロセス」について言及しています...シグナルとスレッドを混在させようとしているわけではないことを願っています。もしそうなら、それには非常に具体的なイディオムが必要です。

于 2011-11-17T01:38:05.570 に答える
2

「シグナルハンドラー[...]が呼び出す」と言うと、設計が間違っていますcriticalFunction。シグナルハンドラーは、深刻な量の作業を行うべきではありません。彼らはそのために作られていません。

シグナルハンドラー内から合理的に行う必要があるのは、型の変数を変更することだけですsigatomic_t。これは通常、フラグを設定するために使用され、コードの残りの部分(メインループなど)は、フラグが設定されているかどうかを定期的にチェックする必要があります。

シグナルハンドラーがそれ以外のことをした場合、それは実際には未定義の動作だと思います。更新: From :「シグナルハンドラー内から安全に呼び出すことができる非同期シグナルセーフ関数のリストをman 2 signal参照してください。」signal(7)

于 2011-11-17T01:12:11.490 に答える