signal
APIは、指定されたシグナルの受信時に呼び出される提供された関数ポインタを登録します。複数の信号に対して同じ関数ポインタを登録することができます。したがって、呼び出されたときに受け取った信号値が関数に渡されます。
Linux(および私が認識しているすべてのオペレーティングシステム)では、シグナルの配信はプロセスの実行とは非同期であり、通知は即時です。 OSはあたかもプログラムをプリエンプトし、プログラムが現在行っている処理の上にシグナルハンドラ関数呼び出しを注入するかのように動作します。 OSはどの信号が送られたのかを認識し、それをパラメータとして関数呼び出しに渡します。
注:プログラムに同期信号を生成するraise
を使用することが可能です。しかし、通常、シグナルハンドラを直接呼び出すのではなく、OSサービスを使用してプロセスに渡します。
デバッガを使用してシグナルハンドラ内でブレークポイントを設定し、適切な信号を送信すると、バックトレースに信号ハンドラがOSによって注入されていることが表示されることがあります。
void signalhandler (int sig)
{
write(2, "signal!\n", 8);
}
void foo (void)
{
for (;;) {}
}
int main (void)
{
signal(SIGINT, signalhandler);
foo();
}
gdb
でプログラムを実行している、あなたはsignal
コマンドを使用して信号を提供することができます:
は例えば、プログラムを検討してください。
(gdb) signal SIGINT
Continuing with signal SIGINT.
Breakpoint 1, signalhandler (sig=2) at s.c:5
5 write(2, "signal!\n", 8);
(gdb) bt
#0 signalhandler (sig=2) at s.c:5
#1 <signal handler called>
#2 foo() at s.c:10
#3 0x08048498 in main() at s.c:16
注:結果のバックトレースは次のようになりますシグナルハンドラ関数の呼び出しは、通常の関数呼び出しのように扱われるべきではないことを認識することが重要です。 OSはコールを注入するので、以下で説明する制限があります。
シグナルコールは、コード実行の任意の場所で注入することができます。このため、POSIXでは、特定の関数をシグナルハンドラから呼び出すことが安全であることを要求しています。リエントラントになるように設計されていない関数は、シグナルハンドラ関数へのインジェクションコールによって中断された場合に矛盾した状態になるリスクを負います。
たとえば、リンクリストからノードを削除するなど、データ構造を操作するコードを記述しているとします。しかし、要素のポインタがシグナルが配信されたときに完全に修正されていない場合、シグナルハンドラは破損したリンクリストを見ることがあります。この状況は、特にヒープ割り当てを必要とする関数を呼び出す場合に想定されるよりも頻繁に発生します。
このように、シグナルハンドラを単純なものにするのは最も安全です。たとえば、シグナルハンドラは単にフラグを設定するだけで、アプリケーションコードはフラグが設定されているかどうかを検出するコードを必要とします。
出典
2016-05-27 07:59:30
jxh
あなたは 'signal'が' signalhandler'を直接呼び出すのではないことを理解しています。 –
あなたはもっと詳しく説明できますか? – raj
別の言い方をすると、「シグナル」はどういう意味ですか? –