実行に時間がかかるプログラムがあります。メインモジュールには次のものがあります。
import signal
def run_program()
...time consuming execution...
def Exit_gracefully(signal, frame):
... log exiting information ...
... close any open files ...
sys.exit(0)
if __name__ == '__main__':
signal.signal(signal.SIGINT, Exit_gracefully)
run_program()
これはうまく機能しますが、SIGINTをキャッチすると実行を一時停止し、本当に終了したい場合はユーザーにプロンプトを表示し、run_program()で終了したくないと判断した場合は中断した場所に再開する可能性が欲しいです。
これを行うことを考えることができる唯一の方法は、プログラムを別のスレッドで実行し、メインスレッドを待機させ、SIGINTをキャッチする準備を整えることです。ユーザーがメインスレッドを終了する場合は、クリーンアップを実行して子スレッドを強制終了できます。
もっと簡単な方法はありますか?
pythonシグナルハンドラーは本当のシグナルハンドラーではないようです;それは、事実の後、通常のフローで、Cハンドラーがすでに戻った後に発生します。シグナルハンドラー内の終了ロジック:シグナルハンドラーはメインスレッドで実行されるため、メインスレッドでも実行がブロックされます。
このような何かがうまくいくようです。
import signal
import time
import sys
def run_program():
while True:
time.sleep(1)
print("a")
def exit_gracefully(signum, frame):
# restore the original signal handler as otherwise evil things will happen
# in raw_input when CTRL+C is pressed, and our signal handler is not re-entrant
signal.signal(signal.SIGINT, original_sigint)
try:
if raw_input("\nReally quit? (y/n)> ").lower().startswith('y'):
sys.exit(1)
except KeyboardInterrupt:
print("Ok ok, quitting")
sys.exit(1)
# restore the exit gracefully handler here
signal.signal(signal.SIGINT, exit_gracefully)
if __name__ == '__main__':
# store the original SIGINT handler
original_sigint = signal.getsignal(signal.SIGINT)
signal.signal(signal.SIGINT, exit_gracefully)
run_program()
このコードは、raw_input
の間、元のシグナルハンドラーを復元します。 raw_input
自体は再入可能ではなく、再入力するとRuntimeError: can't re-enter readline
からtime.sleep
が発生しますが、これはKeyboardInterrupt
。むしろ、2つの連続したCtrl-CでKeyboardInterrupt
を発生させます。
from https://Gist.github.com/rtfpessoa/e3b1fe0bbfcd8ac853bf
#!/usr/bin/env python
import signal
import sys
def signal_handler(signal, frame):
# your code here
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
さようなら!