私は現在、情報を処理する無限ループを持つサーバー上にCで作成したプログラムを持っています。各ループは、完了するのに約5分かかります。シェルスクリプトに次の機能を持たせたいです。
- Cプログラムを終了します
- ソースを作成
- プログラムを実行する
問題は、ctrl + cのようなことをせずにCプログラムを終了するように指示する方法がわからないことです。むしろ、現在作業中の情報の処理を終了してから終了したいと思います。
プロセスにビジネスを終了してクリーンに終了するように指示するPOSIXの標準的な方法は、SIGTERM
シグナルを送信することです。アプリケーションによっては、で終了することが適切な場合とそうでない場合がありますSIGINT
。これは、プロセスを終了するのではなく、中断することを意味します。(Control-cは送信しますSIGINT
。)
タイトなループに旗を立ててみてください。簡単に終了できるときにフラグを確認しますが、それでもすぐに終了するのに十分な頻度です。あなたの場合、を受信するとSIGTERM
すぐにシステムログにメッセージが表示され、5分以内に終了することが約束されます。
シグナルハンドラは次のようになります。
static int signalled; // if nonzero, what signal have we been sent?
static void SignalHandler(int signum) {
signalled = signum;
}
I / O操作のたびにグローバルstatic
変数をチェックしますsignalled
。つまり、1秒間に何度もチェックします。
シグナルをキャッチして復元するための私のコードは次のとおりです。
static __sighandler_t sh, si, st;
static void catch_signals(void) {
if ((sh = signal(SIGHUP, SignalHandler)) == SIG_IGN) signal(SIGHUP, SIG_IGN);
if ((si = signal(SIGINT, SignalHandler)) == SIG_IGN) signal(SIGINT, SIG_IGN);
if ((st = signal(SIGTERM, SignalHandler)) == SIG_IGN) signal(SIGTERM, SIG_IGN);
signalled = 0;
}
static void restore_signals(void) {
signal(SIGHUP, sh);
signal(SIGINT, si);
signal(SIGTERM, st);
}
(このコードはライブラリからのものであるため、見つけたままにしておくように特に注意しています。)
ボーナストリック:時間が経過すると(これはテレビ録画ライブラリです)、タイマーが設定されるだけでsignalled = SIGTERM
、同じロジックがレコーダーを正常に終了するために使用されます。
ctrl + cのように、itelを終了する前に、現在作業中の情報の処理を終了したほうがいいです。
SIGINTまたは必要なもののシグナルハンドラーを確立し、受信後にクリーンアップを実行します。ただし、ハンドラー自体でクリーンアップを実行しないでください。
volatile sig_atomic_t do_cleanup = 0;
void handler(int sig)
{
do_cleanup = 1;
}
次に、メインループで、必要に応じてテストdo_cleanup
して終了する必要があります。EINTR
まだエラーを処理していない場合は、エラーを適切に処理する際にも注意する必要があります。
シェルから信号を送信する方法は次のとおりです。
http://bash.cyberciti.biz/guide/Sending_signal_to_Processes
または単にman kill
信号に反応する方法は次のとおりです。
http://www.cs.cf.ac.uk/Dave/C/node24.html#SECTION002400000000000000000