PythonでUNIXシグナルのハンドラを扱う(後半)
「PythonでUNIXシグナルのハンドラを扱う(前半)」の続き。
UNIXシグナルハンドラ処理に関する特殊な指定
signal.signal()の2番目の引数にsignal.SIG_DFLもしくはsignal.SIG_IGNという値を指定すると、ハンドラが指定される代わりに動作を変更する。
signal.SIG_DFL*1はシグナルに応じた「既定の動作」を行う。SIGINTシグナルを受け取った場合にはKeyboardInterrupt例外を出さずにプログラムを終了する。
# シグナルSIGINTを受け取った場合に # 例外KeyboardInterruptを出さずに終了する signal.signal(signal.SIGINT, signal.SIG_DFL)
signal.SIG_IGN*2ではそのシグナルを無視する(そのシグナルに対して無反応になる)。SIGINTに対してsignal.SIG_IGNを指定するとCtrl+Cを押しても終了ができなくなる。
# シグナルSIGINTを受け取っても無視するようにする場合
signal.signal(signal.SIGINT, signal.SIG_IGN)
KeyboardInterrupt例外の抑制例
前半の例では自作のハンドラの中で終了処理をしたが、下の例ではCtrl+Cを押したときにKeyboardInterruptに関するメッセージを出さずに終了する。
#! /usr/bin/python # -*- encoding: utf-8 -*- import signal import sys import os try: import pygtk pygtk.require('2.0') except: pass try: import gtk except: sys.exit(1) class MainWindow(gtk.Window): """ メインウィンドウ """ def __init__(self, *args, **kwargs): gtk.Window.__init__(self, *args, **kwargs) self.set_title('test') self.set_size_request(320, 200) self.__accelgroup = gtk.AccelGroup() self.add_accel_group(self.__accelgroup) self.__item_quit = gtk.ImageMenuItem(gtk.STOCK_QUIT, self.__accelgroup) self.__menu_file = gtk.Menu() self.__menu_file.add(self.__item_quit) self.__item_file = gtk.MenuItem('_File') self.__item_file.set_submenu(self.__menu_file) self.__menubar = gtk.MenuBar() self.__menubar.append(self.__item_file) self.__button = gtk.Button() self.__button.set_label('Test') self.__statusbar = gtk.Statusbar() self.__vbox = gtk.VBox(False, 0) self.__vbox.pack_start(self.__menubar, expand=False, fill=False) self.__vbox.pack_start(self.__button) self.__vbox.pack_start(self.__statusbar, expand=False, fill=False) self.add(self.__vbox) self.__button.connect('clicked', self.__on_button_clicked) self.__item_quit.connect('activate', gtk.main_quit) self.connect('delete_event', gtk.main_quit) def __on_button_clicked(self, widget): """ ボタンが押されたときの処理 """ print '__on_button_clicked()' class PyGTKUnixSigHandlerTest2: """ UNIXシグナルハンドラのテスト2 """ def main(self): """ ウィンドウを作成してGTK+のメインループを呼ぶ """ # シグナルSIGINTを受け取った場合に # 例外KeyboardInterruptを出さずに終了する signal.signal(signal.SIGINT, signal.SIG_DFL) win = MainWindow() win.show_all() gtk.main() if __name__ == '__main__': app = PyGTKUnixSigHandlerTest2() app.main()
KeyboardInterrupt例外はどこから?
signal.signal()によりUNIXシグナルハンドラの設定を行わない場合に発生するKeyboardInterruptの例外はどこで呼ばれているのかを調べるため、まずはsignal.getsignal()でSIGINTに対応する既定のハンドラを問い合わせてみると
>>> import signal >>> signal.getsignal(signal.SIGINT) <built-in function default_int_handler>
となった。これは関数なので呼び出してみると
>>> signal.getsignal(signal.SIGINT)() Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyboardInterrupt
KeyboardInterrupt例外がここ(signal.default_int_handler()関数の中)で出てきた。文字通り、SIGINT用の既定のハンドラが標準で用意されており、この中で例外を出すようになっているようだ。
関連記事:
- シェル上のプロセスの動作状態(フォアグラウンド/バックグラウンド/サスペンド)とその制御について(前半)
- シェル上のプロセスの動作状態(フォアグラウンド/バックグラウンド/サスペンド)とその制御について(後半)
- UNIXシグナルによるプロセス制御について
- PythonでUNIXシグナルのハンドラを扱う(前半)
参考URL: