6

pのシグナルハンドラに登録されたプロセスがありますSIGALRMSIGALRMprocessに定期的にシグナルを送信するようにタイマーが設定されますp。また、複数のスレッドがプロセスで実行されていますp。トリガーされて実行されたときのシグナルハンドラは、プリエンプティブルではないですか? というか、シグナルハンドラの実行は処理中のどのスレッドにも割り込まれないということpですか?

PS: シグナル ハンドラーはカーネルで実行されると思いましたが (そうですか?)、カーネルはユーザー モード スレッドに対してプリエンプティブではありませんか? 違っていたら訂正...

4

3 に答える 3

16

シグナルハンドラーで共有データを処理すると、ほとんどの場合、スレッドを処理するだけでなく、混乱することになります

デフォルトでは、シグナルハンドラーの実行中はシグナルがブロックされるため (少なくとも Linux では、これは一般的に当てはまらない可能性があります)、少なくともシグナルハンドラー自体がプリエンプトされることはありません。ただし、複数のスレッドがあり、シグナルが他のスレッドでブロックされていない場合、シグナル ハンドラーは複数のスレッド内で同時に実行される可能性があります。

1 つのスレッドがシグナルを受信して​​ハンドラーを実行します。どのスレッドになるかは多かれ少なかれランダムですが、シグナルを処理したくないすべてのスレッドでシグナルをブロックすることで制御できます。

ただし、シグナルを処理するスレッドを妨げる他のスレッドは、並行して実行される可能性があります。シグナルを処理するスレッドは、プログラム内のほぼすべての時点でシグナル ハンドラーを実行できます (シグナルがブロックされない限り)。そのため、そのデータを保護するために何らかのロックが必要になります。問題は、通常のスレッド ロック プリミティブを使用できないことです。これらは、シグナル非同期セーフではありません。たとえば、シグナル ハンドラで pthread_mutex_t を取得しようとすると、プログラムが簡単にデッドロックしてしまいます。

シグナル ハンドラで安全に呼び出すことができる唯一の関数は、ここにリストされているものです。共有データの保護に関しては、一種の保護として sigblock()/sigunblock() を使用して、その共有データにアクセスしている間はシグナル ハンドラが実行されないようにすることができます。そうしないと、ブロックされていないスレッドのいずれかで実行されます。その道を進むのは狂気です。

シグナルハンドラで安全にアクセスできる唯一の共有データはほとんどsig_atomic_t型であり、実際には他の種類のプリミティブ型も通常は安全です。

シグナルハンドラで本当にすべきことは、

  • グローバル フラグを設定する
  • 適切な場合はコードの他の場所でそのフラグを確認し、アクションを実行します

または

  • select()/poll() などを使用してイベントのファイル記述子を監視する何らかのメインループがあります。
  • パイプを作成し、メインループでそれを監視します
  • write() シグナル ハンドラのパイプへのバイト
  • メインループがそのパイプでイベントを検出したときに共有データを保護するなど、コードを実行してシグナルを処理します

または

  • 予備のスレッドを保持する
  • すべてのスレッドで指定されたシグナルをブロックします
  • そのシグナルの配信を保証するシグナルマスクを使用して sigsuspend() を呼び出すときに、予備のスレッドループを用意します。
  • sigsuspend() が返されたときにシグナルを処理するために共有データを保護するなど、コードを実行します
于 2011-05-25T18:23:44.217 に答える
5

トリガーされて実行されたときのシグナルハンドラは、プリエンプティブルではないですか?

いいえ、シグナル ハンドラーは他のユーザー レベル関数と同様にプリエンプティブです。

シグナルハンドラーはカーネルで実行されると思っていました(そうですか?)

いいえ、シグナル ハンドラはカーネル モードでは実行されません。

カーネルは、カーネル モードからユーザー モードに切り替えるときに、プロセスの保留中のシグナルをチェックします。保留中のシグナルが見つかった場合は、ユーザー モードに戻った後にプロセスがシグナル ハンドラーの実行を開始するようにユーザーのスタック フレームをセットアップします。実行が完了すると、プロセスはカーネルモードに切り替わります。次に、カーネルはプロセスの元のコンテキストを復元し、シグナル処理の前に実行します。
このすべてのモード切り替えは魔法ではありません。カーネルは、ユーザー スタック内の適切なリターン アドレスを変更します。

于 2011-05-26T12:28:42.637 に答える