問題の歴史:
Perlはシステムスクリプト用の言語として作成されたため、シグナル管理(SIGTERM、SIGINT、SIGHUP)は常に組み込まれた強力な機能です。このシステムにより、外部イベント(ユーザーの停止、デーモンの再起動、タイムアウト)をキャッチし、スクリプトの動作を適切に終了させたり変更したりできます。
問題:
シグナルの不適切な処理は、スクリプトの不正終了やハング、緊急終了時のデータ損失、状態やリソースの損失なしにプロセスを再起動することができない原因の一般的です。
解決策:
シグナルは特別なハッシュ %SIG にハンドラを設定することで処理されます。シグナルハンドラ内でのアクションは最小限にすることが良いプラクティスです(例えば、フラグを設定し、メインスレッドで安全に終了します)。スレッド内での正しい動作とシグナルの重複処理には、専門のモジュール(例:POSIX::sigaction)を使用します。
例:
my $term = 0; $SIG{TERM} = sub { $term = 1; }; while (1) { last if $term; # 主な作業 } print "優雅なシャットダウン ";
主な特徴:
シグナルハンドラ内でprint/IOを使用することはできますか?
答え: 推奨されません — 不正な動作が発生し、データの損失の可能性があります!現代の標準は、ミニマルコード(フラグの設定/変数のクリアのみ)です。
最初の発生後にシグナルハンドラをリセットしなかった場合、何が起こりますか?
答え: シグナルが再度発生すると、ハンドラは何度も実行されます。最初のイベントのみに反応する必要がある場合、ハンドラは自ら$SIG{...}をリセットするか、自信にシグナルを送る必要があります。
Perlにおけるシグナル処理はスレッドセーフですか?
答え: いいえ!マルチスレッドのPerlでは、シグナルハンドラはメインスレッド(メインインタープリタ)でのみ呼び出され、スレッド内ではシグナルが完全に無視されたり、不正に処理されたりする可能性があります。
デーモンプログラムがSIGTERMを受信するとすぐに、すべてのファイルディスクリプタでcloseを呼び出し、ハンドラ内で一時ファイルを削除します — 時折ファイルが削除されず、データが失われます。
利点:
欠点:
SIGTERMのシグナルハンドラは、$exit変数だけを設定し、その後メインループは注意深く動作を終了し、ファイルを閉じてからリソースを解放します。
利点:
欠点: