Pythonのsignalモジュールを使ってシグナルハンドラの処理を行う方法

スポンサーリンク

今回は、Pythonのsignalモジュールの使い方を紹介します。

このモジュールは、Pythonを使ってある種のシグナルを処理したいときに非常に便利です。

まず、シグナルが何を意味するのかを見てみましょう。

スポンサーリンク

信号とは

シグナルは、プログラムがオペレーティング・システムから情報を受け取るための手段です。

オペレーティングシステムはあるイベントを受け取ると、それをシグナルの形でプログラムに渡すことができます。

例えば、キーボードで「Ctrl + C」というキーストロークを押すと、オペレーティングシステムはシグナルを生成し、これをプログラムに渡します。

この特定の組み合わせでは、信号 SIGINT が生成され、プログラムに渡されます。

一般的なオペレーティングシステムでは、これらのシグナルを割り当てるための標準的なパターンがあり、それらは一般的に整数の略語です。

Pythonでは、これらのシグナルは signal モジュールで定義されています。

import signal

あなたのシステムで有効なシグナルをすべて見るには(OSに依存します)、 signal.valid_signals() を使用することができます。

import signal
 
valid_signals = signal.valid_signals()
 
print(valid_signals)

結果は以下の通りです。

{<Signals.SIGHUP: 1>, <Signals.SIGINT: 2>, <Signals.SIGQUIT: 3>, <Signals.SIGILL: 4>, <Signals.SIGTRAP: 5>, <Signals.SIGABRT: 6>, <Signals.SIGBUS: 7>, <Signals.SIGFPE: 8>, <Signals.SIGKILL: 9>, <Signals.SIGUSR1: 10>, <Signals.SIGSEGV: 11>, <Signals.SIGUSR2: 12>, <Signals.SIGPIPE: 13>, <Signals.SIGALRM: 14>, <Signals.SIGTERM: 15>, 16, <Signals.SIGCHLD: 17>, <Signals.SIGCONT: 18>, <Signals.SIGSTOP: 19>, <Signals.SIGTSTP: 20>, <Signals.SIGTTIN: 21>, <Signals.SIGTTOU: 22>, <Signals.SIGURG: 23>, <Signals.SIGXCPU: 24>, <Signals.SIGXFSZ: 25>, <Signals.SIGVTALRM: 26>, <Signals.SIGPROF: 27>, <Signals.SIGWINCH: 28>, <Signals.SIGIO: 29>, <Signals.SIGPWR: 30>, <Signals.SIGSYS: 31>, <Signals.SIGRTMIN: 34>, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, <Signals.SIGRTMAX: 64>}

さて、すべてのシグナルに対して、OSがすべてのプログラムに割り当てるいくつかのデフォルトの動作があります。

もし、他の動作をさせたければ、シグナルハンドラを使えばいいのです。

Python Signal Handler とは何ですか?

シグナルハンドラとは、Pythonのシグナルを処理するためのユーザー定義関数のことです。

もしシグナル SIGINT (Interrupt Signal) を受け取ると、デフォルトの動作は現在実行中のプログラムを停止することでしょう。

しかし、このシグナルを検出するシグナルハンドラを割り当てて、代わりに独自の処理を行うことができます。

それでは、その方法を見てみましょう。

import signal 
import time 
 
# Our signal handler
def signal_handler(signum, frame): 
    print("Signal Number:", signum, " Frame: ", frame) 
 
def exit_handler(signum, frame):
    print('Exiting....')
    exit(0)
 
# Register our signal handler with `SIGINT`(CTRL + C)
signal.signal(signal.SIGINT, signal_handler)
 
# Register the exit handler with `SIGTSTP` (Ctrl + Z)
signal.signal(signal.SIGTSTP, exit_handler)
 
# While Loop
while 1
    print("Press Ctrl + C")
    time.sleep(3)

ここでは、プログラムを実行した後、Ctrl + C を押すと、SIGINT (Ctrl + C) にハンドラを登録しているので、プログラムは signal_handler() 関数に移動します。

また、もう一つのハンドラ exit_handler() があり、Ctrl + Z を押すと SIGTSTP シグナルが送られ、プログラムを終了させることができます。

出力を見てみましょう。

結果は以下の通りです。

Press Ctrl + C
^CSignal Number: 2  Frame:  <frame at 0x7fe62f033640, file 'python_signals.py', line 22, code <module>>
^ZExiting....

ここでは、Ctrl + C を押して signal_handler() 関数に移動し、Ctrl + Z を押してプログラムを終了しています。

メインプログラムの実行時スタックを追跡するために、スタックフレームオブジェクト (frame) も存在することに注意してください。

アラーム信号の利用

SIGALARM` シグナルを使用して、プログラムにアラームシグナルを送信することができます

この Python シグナルを処理する簡単なシグナルハンドラを書いてみましょう。

import signal 
import time 
 
def alarm_handler(signum, frame): 
    print('Alarm at:', time.ctime()) 
 
# Register the alarm signal with our handler
signal.signal(signal.SIGALRM, alarm_handler)
 
signal.alarm(3# Set the alarm after 3 seconds 
 
print('Current time:', time.ctime()) 
 
time.sleep(6# Make a sufficient delay for the alarm to happen

最後の行では、アラームシグナルがプログラムに伝わるように十分な時間(6秒)スリープしています。

結果は以下の通りです。

Current time: Thu Jul 23 00:41:40 2020
Alarm at: Thu Jul 23 00:41:43 2020

まとめ

この記事では、signalモジュールを使用して、様々なシグナルを処理するシグナルハンドラを設定する方法について学びました。

Pythonのモジュールについてもっと知りたい方はこちらをご覧ください。

参考文献

  • Python signal モジュール ドキュメント
  • Python シグナルに関する JournalDev の記事
タイトルとURLをコピーしました