[Q-3]私の例のterminate
変数は でなければなりvolatile
ませんか? この変数が揮発性である多くの例と、そうでない他の例を見てきました。
フラグterminate
はvolatile sig_atomic_t
次のとおりです。
ハンドラー関数は非同期で呼び出すことができるためです。つまり、ハンドラはプログラムの任意の時点で予期せず呼び出される可能性があります。非常に短い間隔で 2 つのシグナルが到着した場合、1 つのハンドラーが別のハンドラー内で実行できます。また、 を宣言することをvolatile sig_atomic_t
お勧めします。この型は常にアトミックにアクセスされ、変数へのアクセスの中断に関する不確実性を回避します。volatile
最適化しないようにコンパイラーに指示し、それをレジスターに入れます。(読み取り:詳細な有効期限のためのアトミック データ アクセスとシグナル処理)。
もう 1 つの参照: 24.4.7 Atomic Data Access and Signal Handling。さらに、7.14.1.1-5 の C11 標準はvolatile sig_atomic_t
、シグナル ハンドラからは のオブジェクトのみにアクセスできることを示しています (他のオブジェクトへのアクセスは未定義の動作をします)。
[Q-4]signal()
が非推奨になり、使用することを読みましたsigaction()
。signal()
以前の呼び出しから変換する方法を示す本当に良い例はありますか? 作成/渡す必要がある新しい構造と、それらがどのように適合するかについて問題があります。
以下の例 (およびコメント内のリンク) が役立ちます。
// 1. Prepare struct
struct sigaction sa;
sa.sa_handler = sighandler;
// 2. To restart functions if interrupted by handler (as handlers called asynchronously)
sa.sa_flags = SA_RESTART;
// 3. Set zero
sigemptyset(&sa.sa_mask);
/* 3b.
// uncomment if you wants to block
// some signals while one is executing.
sigaddset( &sa.sa_mask, SIGINT );
*/
// 4. Register signals
sigaction( SIGINT, &sa, NULL );
参照:
- Beginning Linux Programming, 4th Edition : この本では
sigaction()
、「Chapter 11: Processes and Signals」で正確にコードが説明されています。
- 例を含む sigaction ドキュメント(クイック ラーニング)。
- The GNU C Library: Signal Handling
*1 から始めて、現在3 つの GNU-libraryを読んでいます
[Q-5]への2回目の呼び出しはsignal()
必要ですか? 私が心配する必要がある同様のものはありsigaction()
ますか?
プログラムの終了前に default-action に設定した理由は、私にはわかりません。次の段落が答えになると思います。
signal の呼び出しは、シグナルの1 回だけの発生に対するシグナル処理を確立します。シグナル処理関数が呼び出される前に、ライブラリはシグナルをリセットして、同じシグナルが再び発生した場合にデフォルトのアクションが実行されるようにします。シグナル処理をリセットすると、たとえば、シグナル ハンドラーで実行されたアクションが同じシグナルを再び発生させた場合に、無限ループを防ぐのに役立ちます。ハンドラーをシグナルが発生するたびに使用する場合は、ハンドラー内でシグナルを呼び出して元に戻す必要があります。シグナル処理を元に戻す際には注意が必要です。たとえば、継続的にSIGINT
処理を再開すると、プログラムを中断して終了することができなくなる可能性があります。
このsignal()
関数は、次に受信したシグナルのハンドラーのみを定義し、その後、デフォルトのハンドラーが復元されます。したがってsignal()
、プログラムがデフォルト以外のハンドラーを使用してシグナルの処理を続行する必要がある場合は、シグナル ハンドラーを呼び出す必要があります。
詳細については、ディスカッションを参照してください:シグナル ハンドラーを再度有効にする場合。
【Q-1a】シグナルハンドリングは必要ですか?
はい、Linux がクリーンアップを行います。たとえば、ファイルまたはソケットを閉じない場合、Linux はプロセスの終了後にクリーンアップを行います。ただし、Linux はすぐにクリーンアップを実行する必要はなく、時間がかかる場合があります (システム パフォーマンスを高く維持するため、またはその他の問題が原因である可能性があります)。たとえば、tcp ソケットを閉じずにプログラムが終了した場合、カーネルはソケットをすぐに閉じず、すべてのデータが送信されたことを確認します。可能であれば、TCP が配信を保証します。
[Q-1b]したがって、シグナル ハンドラを無限ループだけに置き換えて、OS にスレッドを正常に終了させたり、メモリの割り当てを解除させたりすることはできますか?
いいえ、オペレーティング システムは、プログラムの終了後にのみクリーンアップを実行します。プロセスの実行中、そのプロセスに割り当てられたリソースは OS によって要求されません。(OS は、プロセスが無限ループにあるかどうかを認識できません。これは解決できない問題です)。プロセスの終了後に OS がクリーンアップ操作を実行するようにしたい場合は、シグナルを処理する必要はありません (プロセスがシグナルによって異常終了した場合でも)。
[Q]私が達成しようとしているのは、ctrlc電源が切断されるか、何か本当に悪いことが起こるまで、 my: メイン ループを実行することだけです。
いいえ、制限があります!すべての信号をキャッチすることはできません。一部のシグナルはキャッチできません。たとえばSIGKILL
、and とSIGSTOP
and の両方が終了シグナルです。1つ引用:
このSIGKILL
信号は、プログラムを即時終了させるために使用されます。これは処理または無視できないため、常に致命的です。この信号をブロックすること もできません。
したがって、中断できないプログラム (中断されないプログラム) を作成することはできません。
確かではありませんが、Windows システムでこのようなことができるかもしれません: TSR (ある種のカーネル モード フック) を書くことによって。論文の時から、一部のウイルスはタスク マネージャーからでも終了できないことを覚えていますが、それらは管理者権限によってユーザーを騙していると考えています。
この回答がお役に立てば幸いです。