私の実験コードは次のようなものです:
import signal
def hi(signum, frame):
print "hi"
signal.signal(signal.SIGINT, hi)
signal.signal(signal.SIGINT, signal.SIG_IGN)
hi
シグナル ハンドラが によってオーバーライドされるため、出力されませんでしたsignal.SIG_IGN
。
どうすればこれを回避できますか?
ハンドラーが既に存在するかどうかを確認してみてください。その場合は、目的のハンドラーと古いハンドラーを、両方を呼び出すラッパー関数に配置します。
def append_signal(sig, f):
old = None
if callable(signal.getsignal(sig)):
old = signal.getsignal(sig)
def helper(*args, **kwargs):
if old is not None:
old(*args, **kwargs)
f(*args, **kwargs)
signal.signal(sig, helper)
独自のハンドラーをオーバーライドしたくない場合は、ハンドラーが設定されているかどうかを確認してください。
if signal.getsignal(signal.SIGINT) in [signal.SIG_IGN, signal.SIG_DFL]:
signal.signal(signal.SIGINT, hi)
ドキュメントによると、上位のプロセスがすでにデフォルトからハンドラーを再割り当てしている可能性があります。それをオーバーライドしたくない場合はNone
、シグナルのリストに追加します。
の明らかなラッパーsignal.signal(..., signal.SIG_IGN)
はnot in
テストです。
コメントに応じて追加
シグナルは非常に粒状であるため、シグナルハンドラの連鎖はあまり行われません。本当にこれをやりたいのであれば、atexitのモデルに従い、ハンドラーによって呼び出される関数を登録します。
C で行う場合と同じように行うだけです。
sig_hand_prev = None
def signal_handler(signum, frame):
...
signal.signal(signum, sig_hand_prev)
os.kill(os.getpid(), signum)
def install_handler(signum):
global sig_hand_prev
sig_hand_prev = signal.signal(signum, signal_handler)
ここでの重要なアイデアは、前のハンドラーのみを保存し、作業が終了したときに再び発生させることです。このように、シグナル処理は単一のリンクされたリスト OOB です。