SIGINTのキャプチャと終了処理

PythonプログラムをCtrl+Cで中断するとき、SIGINT(シグナル番号2)が送信されます。これをキャプチャして適切に終了処理を行うためには、“signalモジュールを使用します。

基本的なシグナルハンドラの実装

signalモジュールを使って、SIGINTをキャプチャし、Gracefulにプログラムを終了させる例を紹介します。

import signal
import sys
def signal_handler(sig, frame):
    print('You pressed Ctrl+C!')
    sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C to exit')
signal.pause()

signal.signal()SIGINTを指定し、キャプチャ後にsys.exit(0)で安全に終了します。

KeyboardInterruptとの違い

Ctrl+Cをキャプチャする方法としては、KeyboardInterruptを使うこともできますが、signal.signal()を使うと、kill -SIGINTコマンドや他のシグナル送信方法にも対応できます。

try:
    while True:
        # 長時間のタスク
        pass
except KeyboardInterrupt:
    print("Graceful shutdown...")

KeyboardInterruptは特定の例外処理で簡単に扱えますが、シグナルハンドラを使うと、プログラム全体での一貫した制御が可能です。

コンテキストマネージャによるシグナルハンドリング

複雑なケースでは、コンテキストマネージャを使ってシグナルハンドリングを簡潔にすることもできます。次の例では、GracefulInterruptHandlerというクラスを定義し、複数のシグナルを管理します。

import signal
from contextlib import contextmanager
class GracefulInterruptHandler:
    def __init__(self):
        self.interrupted = False
    def __enter__(self):
        self.old_handler = signal.getsignal(signal.SIGINT)
        signal.signal(signal.SIGINT, self.handler)
        return self
    def handler(self, signum, frame):
        self.interrupted = True
    def __exit__(self, exc_type, exc_val, exc_tb):
        signal.signal(signal.SIGINT, self.old_handler)
with GracefulInterruptHandler() as h:
    while not h.interrupted:
        print("Running...")

このようにして、Ctrl+Cが押されたときにGracefulにプログラムを終了させることができます。

まとめ

PythonSIGINTをキャプチャするには、signal.signal()を使う方法が便利です。特に複数のシグナルやカスタム処理を扱いたい場合、シグナルハンドラを使用することで柔軟なプログラムが実現できます。また、シンプルなケースではKeyboardInterruptでも対応可能です。