signal —非同期イベントのハンドラーを設定します
このモジュールは、Pythonでシグナルハンドラーを使用するメカニズムを提供します。
一般的なルール
signal.signal()関数を使用すると、シグナルを受信したときに実行されるカスタムハンドラーを定義できます。 少数のデフォルトハンドラーがインストールされます。 SIGPIPE は無視され(したがって、パイプとソケットの書き込みエラーは通常のPython例外として報告されます)、 SIGINT は KeyboardInterruptに変換されます。 親プロセスが変更していない場合の例外。
特定のシグナルのハンドラーは、一度設定されると、明示的にリセットされるまでインストールされたままになります(Pythonは、基になる実装に関係なくBSDスタイルのインターフェースをエミュレートします)。ただし、基になる SIGCHLD のハンドラーは例外です。実装。
Pythonシグナルハンドラーの実行
Pythonシグナルハンドラーは、低レベル(C)シグナルハンドラー内では実行されません。 代わりに、低レベルのシグナルハンドラーは、仮想マシンに対応するPythonシグナルハンドラーを後の時点(たとえば、次のバイトコード命令)で実行するように指示するフラグを設定します。 これは結果をもたらします:
- Cコードの無効な操作によって引き起こされる SIGFPE や SIGSEGV のような同期エラーをキャッチすることはほとんど意味がありません。 PythonはシグナルハンドラーからCコードに戻ります。これにより、同じシグナルが再び発生する可能性があり、Pythonが明らかにハングします。 Python 3.3以降では、 faulthandler モジュールを使用して同期エラーを報告できます。
- 純粋にCで実装された長時間実行の計算(大量のテキストでの正規表現マッチングなど)は、受信した信号に関係なく、任意の時間中断することなく実行できます。 計算が終了すると、Pythonシグナルハンドラーが呼び出されます。
シグナルとスレッド
Pythonシグナルハンドラーは、シグナルが別のスレッドで受信された場合でも、常にメインのPythonスレッドで実行されます。 これは、シグナルをスレッド間通信の手段として使用できないことを意味します。 代わりに、 threading モジュールの同期プリミティブを使用できます。
さらに、メインスレッドのみが新しいシグナルハンドラーを設定できます。
モジュールの内容
バージョン3.5で変更:シグナル(SIG *)、ハンドラー( SIG_DFL 、 SIG_IGN )、およびsigmask( SIG_BLOCK 、 SIG_UNBLOCK 、 SIG_SETMASK )に関連する以下の定数は、列挙型に変換されました。 getsignal()、 pthread_sigmask()、 sigpending()、および sigwait()関数は、人間が読める形式の列挙型[X139X ]。
signal モジュールで定義されている変数は次のとおりです。
- signal.SIG_DFL
- これは、2つの標準的な信号処理オプションの1つです。 シグナルのデフォルト機能を実行するだけです。 たとえば、ほとんどのシステムでは、
SIGQUIT
のデフォルトのアクションはコアをダンプして終了することですが、 SIGCHLD のデフォルトのアクションは単にそれを無視することです。
- signal.SIG_IGN
- これは別の標準的なシグナルハンドラーであり、指定されたシグナルを単に無視します。
- signal.SIGABRT
- abort(3)からの信号を中止します。
- signal.SIGALRM
- alarm(2)からのタイマー信号。
- signal.SIGBREAK
- キーボードからの割り込み(CTRL + BREAK)。
- signal.SIGBUS
- バスエラー(メモリアクセス不良)。
- signal.SIGCHLD
- 子プロセスが停止または終了しました。
- signal.SIGCLD
- SIGCHLD のエイリアス。
- signal.SIGCONT
- 現在停止している場合は、プロセスを続行します
- signal.SIGFPE
浮動小数点例外。 たとえば、ゼロによる除算。
も参照してください
ZeroDivisionError は、除算またはモジュロ演算の2番目の引数がゼロの場合に発生します。
- signal.SIGHUP
- 制御端末でのハングアップまたは制御プロセスの停止が検出されました。
- signal.SIGILL
- 違法な指示。
- signal.SIGINT
キーボードからの割り込み(CTRL + C)。
デフォルトのアクションは、 KeyboardInterrupt を上げることです。
- signal.SIGKILL
信号を殺します。
キャッチ、ブロック、または無視することはできません。
- signal.SIGPIPE
壊れたパイプ:リーダーなしでパイプに書き込みます。
デフォルトのアクションは、信号を無視することです。
- signal.SIGSEGV
- セグメンテーション違反:無効なメモリ参照。
- signal.SIGTERM
- 終了信号。
- signal.SIGUSR1
- ユーザー定義の信号1。
- signal.SIGUSR2
- ユーザー定義の信号2。
- signal.SIGWINCH
- ウィンドウサイズ変更信号。
- SIG*
- すべての信号番号はシンボリックに定義されています。 たとえば、ハングアップ信号は signal.SIGHUP として定義されます。 変数名は、
<signal.h>
にあるように、Cプログラムで使用される名前と同じです。 'signal()
'のUnixマニュアルページには、既存のシグナルがリストされています(一部のシステムでは、これは signal(2)であり、他のシステムでは、リストは signal(7)にあります。 )。 すべてのシステムが同じ信号名のセットを定義しているわけではないことに注意してください。 システムによって定義された名前のみがこのモジュールによって定義されます。
- signal.CTRL_C_EVENT
Ctrl + C キーストロークイベントに対応する信号。 この信号は、 os.kill()でのみ使用できます。
バージョン3.2の新機能。
- signal.CTRL_BREAK_EVENT
Ctrl + Break キーストロークイベントに対応する信号。 この信号は、 os.kill()でのみ使用できます。
バージョン3.2の新機能。
- signal.NSIG
- 最高信号番号の番号より1つ多い。
- signal.ITIMER_REAL
- インターバルタイマーをリアルタイムでデクリメントし、満了時に SIGALRM を配信します。
- signal.ITIMER_VIRTUAL
- プロセスの実行時にのみインターバルタイマーをデクリメントし、満了時にSIGVTALRMを配信します。
- signal.ITIMER_PROF
- プロセスの実行時とシステムがプロセスに代わって実行しているときの両方で、インターバルタイマーをデクリメントします。 ITIMER_VIRTUALと組み合わせて、このタイマーは通常、ユーザーおよびカーネル空間でアプリケーションが費やした時間をプロファイリングするために使用されます。 SIGPROFは有効期限が切れると配信されます。
- signal.SIG_BLOCK
how パラメーターから pthread_sigmask()への可能な値は、信号がブロックされることを示します。
バージョン3.3の新機能。
- signal.SIG_UNBLOCK
how パラメーターから pthread_sigmask()への可能な値は、信号のブロックが解除されることを示します。
バージョン3.3の新機能。
- signal.SIG_SETMASK
how パラメーターの pthread_sigmask()への可能な値は、シグナルマスクが置き換えられることを示します。
バージョン3.3の新機能。
signal モジュールは、1つの例外を定義します。
- exception signal.ItimerError
基になる setitimer()または getitimer()実装からのエラーを通知するために発生します。 無効なインターバルタイマーまたは負の時間が setitimer()に渡された場合、このエラーが発生する可能性があります。 このエラーは OSError のサブタイプです。
signal モジュールは、次の機能を定義します。
- signal.alarm(time)
- time がゼロ以外の場合、この関数は SIGALRM シグナルを time 秒でプロセスに送信するように要求します。 以前にスケジュールされたアラームはキャンセルされます(一度にスケジュールできるアラームは1つだけです)。 戻り値は、以前に設定されたアラームが配信されるまでの秒数です。 time がゼロの場合、アラームはスケジュールされず、スケジュールされたアラームはキャンセルされます。 戻り値がゼロの場合、現在アラームはスケジュールされていません。
- signal.getsignal(signalnum)
- シグナル signalnum の現在のシグナルハンドラーを返します。 戻り値は、呼び出し可能なPythonオブジェクト、または特別な値 signal.SIG_IGN 、 signal.SIG_DFL 、または None のいずれかです。 ここで、 signal.SIG_IGN は信号が以前に無視されたことを意味し、 signal.SIG_DFL は信号を処理するデフォルトの方法が以前に使用されていたことを意味し、
None
は以前のシグナルハンドラーがPythonからインストールされていないこと。
- signal.strsignal(signalnum)
「割り込み」、「セグメンテーション違反」など、信号 signalnum のシステム記述を返します。 信号が認識されない場合は、 None を返します。
バージョン3.8の新機能。
- signal.valid_signals()
このプラットフォームで有効な信号番号のセットを返します。 一部の信号がシステムによって内部使用のために予約されている場合、これは
range(1, NSIG)
よりも小さくなる可能性があります。バージョン3.8の新機能。
- signal.pause()
シグナルが受信されるまでプロセスをスリープ状態にします。 次に、適切なハンドラーが呼び出されます。 何も返しません。
sigwait()、 sigwaitinfo()、 sigtimedwait()、および sigpending()も参照してください。
- signal.raise_signal(signum)
呼び出しプロセスにシグナルを送信します。 何も返しません。
バージョン3.8の新機能。
- signal.pthread_kill(thread_id, signalnum)
シグナル signalnum を、呼び出し元と同じプロセス内の別のスレッドであるスレッド thread_id に送信します。 ターゲットスレッドは、任意のコード(Pythonかどうか)を実行できます。 ただし、ターゲットスレッドがPythonインタープリターを実行している場合、Pythonシグナルハンドラーはメインスレッドによって実行されます。 したがって、特定のPythonスレッドにシグナルを送信する唯一のポイントは、実行中のシステムコールを InterruptedError で強制的に失敗させることです。
threading.get_ident()または threading.Thread オブジェクトの ident 属性を使用して、 thread_id の適切な値を取得します。
signalnum が0の場合、シグナルは送信されませんが、エラーチェックは引き続き実行されます。 これを使用して、ターゲットスレッドがまだ実行されているかどうかを確認できます。
os.kill()も参照してください。
バージョン3.3の新機能。
- signal.pthread_sigmask(how, mask)
呼び出し元のスレッドのシグナルマスクをフェッチおよび/または変更します。 シグナルマスクは、発信者に対して現在配信がブロックされているシグナルのセットです。 古い信号マスクを信号のセットとして返します。
呼び出しの動作は、次のように how の値に依存します。
SIG_BLOCK :ブロックされた信号のセットは、現在のセットと mask 引数の和集合です。
SIG_UNBLOCK :マスクの信号は、現在ブロックされている信号のセットから削除されます。 ブロックされていない信号のブロックを解除しようとしてもかまいません。
SIG_SETMASK :ブロックされた信号のセットは mask 引数に設定されます。
マスクは信号番号のセットです(例: { signal.SIGINT 、 signal.SIGTERM })。 すべての信号を含む完全なマスクには、 valid_signals()を使用します。
たとえば、
signal.pthread_sigmask(signal.SIG_BLOCK, [])
は、呼び出し元のスレッドのシグナルマスクを読み取ります。SIGKILL および
SIGSTOP
はブロックできません。pause()、 sigpending()、および sigwait()も参照してください。
バージョン3.3の新機能。
- signal.setitimer(which, seconds, interval=0.0)
で指定されたインターバルタイマー( signal.ITIMER_REAL 、 signal.ITIMER_VIRTUAL 、 signal.ITIMER_PROF のいずれか)をで指定しての後に起動するように設定します。 X168X]秒(フロートが受け入れられ、 alarm()とは異なります)、その後は間隔秒ごと(間隔がゼロ以外の場合)。 で指定されたインターバルタイマーは、秒をゼロに設定することでクリアできます。
インターバルタイマーが作動すると、信号がプロセスに送信されます。 送信される信号は、使用されているタイマーによって異なります。 signal.ITIMER_REAL は SIGALRM を配信し、 signal.ITIMER_VIRTUAL は
SIGVTALRM
を送信し、 signal.ITIMER_PROF はSIGPROF
。古い値はタプルとして返されます:(遅延、間隔)。
無効なインターバルタイマーを通過させようとすると、 ItimerError が発生します。
- signal.getitimer(which)
- which で指定されたインターバルタイマーの現在値を返します。
- signal.set_wakeup_fd(fd, *, warn_on_full_buffer=True)
ウェイクアップファイル記述子を fd に設定します。 信号を受信すると、信号番号が1バイトとしてfdに書き込まれます。 これをライブラリで使用して、ポーリングまたは選択呼び出しをウェイクアップし、信号を完全に処理できるようにすることができます。
古いウェイクアップfdが返されます(またはファイル記述子ウェイクアップが有効になっていない場合は-1)。 fd が-1の場合、ファイル記述子のウェイクアップは無効になります。 -1でない場合、 fd は非ブロッキングである必要があります。 ポーリングを呼び出す前、または再度選択する前に、 fd からバイトを削除するのはライブラリの責任です。
スレッドが有効になっている場合、この関数はメインスレッドからのみ呼び出すことができます。 他のスレッドから呼び出そうとすると、 ValueError 例外が発生します。
この関数を使用する一般的な方法は2つあります。 どちらのアプローチでも、信号が到着したときにfdを使用してウェイクアップしますが、どの信号が到着したかを判断する方法が異なります。
最初のアプローチでは、fdのバッファからデータを読み取り、バイト値から信号番号を取得します。 これは単純ですが、まれに問題が発生する可能性があります。通常、fdのバッファスペースの量は限られており、到着する信号が多すぎると、バッファがいっぱいになり、一部の信号が失われる可能性があります。 このアプローチを使用する場合は、
warn_on_full_buffer=True
を設定する必要があります。これにより、少なくとも信号が失われたときにstderrに警告が出力されます。2番目のアプローチでは、ウェイクアップにwakeup fd only を使用し、実際のバイト値を無視します。 この場合、私たちが気にするのは、fdのバッファが空か空でないかだけです。 バッファがいっぱいになっても、問題はまったくありません。 このアプローチを使用する場合は、
warn_on_full_buffer=False
を設定して、ユーザーが誤った警告メッセージで混乱しないようにする必要があります。バージョン3.5で変更: Windowsでは、この関数はソケットハンドルもサポートするようになりました。
バージョン3.7で変更:
warn_on_full_buffer
パラメーターが追加されました。
- signal.siginterrupt(signalnum, flag)
システムコールの再起動動作の変更:フラグが False の場合、信号 signalnum によって中断されるとシステムコールが再開されます。それ以外の場合、システムコールは中断されます。 何も返しません。
signal()を使用してシグナルハンドラーをインストールすると、指定されたシグナルの真のフラグ値を使用して
siginterrupt()
を暗黙的に呼び出すことにより、再起動動作が割り込み可能にリセットされることに注意してください。
- signal.signal(signalnum, handler)
シグナル signalnum のハンドラーを関数 handler に設定します。 handler は、2つの引数(以下を参照)をとる呼び出し可能なPythonオブジェクト、または特別な値 signal.SIG_IGN または signal.SIG_DFL のいずれかです。 以前のシグナルハンドラーが返されます(上記の getsignal()の説明を参照してください)。 (詳細については、Unixのマニュアルページ signal(2)を参照してください。)
スレッドが有効になっている場合、この関数はメインスレッドからのみ呼び出すことができます。 他のスレッドから呼び出そうとすると、 ValueError 例外が発生します。
ハンドラーは、信号番号と現在のスタックフレーム(
None
またはフレームオブジェクト。フレームオブジェクトの説明については、タイプのの説明を参照)の2つの引数で呼び出されます。階層または inspect モジュールの属性の説明を参照してください)。Windowsでは、 signal()は、 SIGABRT 、 SIGFPE 、 SIGILL 、 SIGINT 、[ X123X] SIGSEGV 、 SIGTERM 、または SIGBREAK 。 それ以外の場合は、 ValueError が発生します。 すべてのシステムが同じ信号名のセットを定義しているわけではないことに注意してください。 信号名が
SIG*
モジュールレベル定数として定義されていない場合、 AttributeError が発生します。
- signal.sigpending()
呼び出しスレッドへの配信が保留されている一連のシグナル(つまり、ブロック中に発生したシグナル)を調べます。 保留中のシグナルのセットを返します。
pause()、 pthread_sigmask()、および sigwait()も参照してください。
バージョン3.3の新機能。
- signal.sigwait(sigset)
シグナルセット sigset で指定されたシグナルの1つが配信されるまで、呼び出しスレッドの実行を一時停止します。 この関数はシグナルを受け入れ(シグナルの保留リストから削除し)、シグナル番号を返します。
pause()、 pthread_sigmask()、 sigpending()、 sigwaitinfo()、 sigtimedwait()も参照してください。 ]。
バージョン3.3の新機能。
- signal.sigwaitinfo(sigset)
シグナルセット sigset で指定されたシグナルの1つが配信されるまで、呼び出しスレッドの実行を一時停止します。 この関数はシグナルを受け入れ、保留中のシグナルのリストからそれを削除します。 sigset のシグナルの1つが呼び出し元のスレッドに対してすでに保留中の場合、関数はそのシグナルに関する情報をすぐに返します。 配信された信号に対してシグナルハンドラーは呼び出されません。 この関数は、 sigset にない信号によって中断された場合、 InterruptedError を発生させます。
戻り値は、
siginfo_t
構造に含まれるデータを表すオブジェクトです。つまり、si_signo
、si_code
、si_errno
、si_pid
、si_uid
、si_status
、si_band
。pause()、 sigwait()、および sigtimedwait()も参照してください。
バージョン3.3の新機能。
バージョン3.5で変更: sigset にないシグナルによって中断され、シグナルハンドラーが例外を発生させない場合、関数が再試行されるようになりました( を参照)。理論的根拠についてはPEP475 )。
- signal.sigtimedwait(sigset, timeout)
sigwaitinfo()と同様ですが、タイムアウトを指定する追加の timeout 引数を取ります。 timeout が
0
として指定されている場合、ポーリングが実行されます。 タイムアウトが発生した場合、 None を返します。pause()、 sigwait()、および sigwaitinfo()も参照してください。
バージョン3.3の新機能。
バージョン3.5で変更: sigset にないシグナルによって中断され、シグナルハンドラーが例外を発生させない場合、関数は再計算された timeout で再試行されるようになりました(理論的根拠については、 PEP 475 を参照してください)。
例
これが最小限のサンプルプログラムです。 alarm()関数を使用して、ファイルを開くのを待つ時間を制限します。 これは、ファイルがオンになっていない可能性のあるシリアルデバイス用である場合に役立ちます。これにより、通常、 os.open()が無期限にハングします。 解決策は、ファイルを開く前に5秒のアラームを設定することです。 操作に時間がかかりすぎると、アラーム信号が送信され、ハンドラーが例外を発生させます。
SIGPIPEに関する注記
プログラムの出力を head(1)などのツールにパイプすると、標準出力のレシーバーが早く閉じると、 SIGPIPE シグナルがプロセスに送信されます。 これにより、BrokenPipeError: [Errno 32] Broken pipe
のような例外が発生します。 このケースを処理するには、次のようにエントリポイントをラップして、この例外をキャッチします。
BrokenPipeError を回避するために、 SIGPIPE の処理を SIG_DFL に設定しないでください。 これを行うと、プログラムがまだ書き込みを行っている間にソケット接続が中断された場合でも、プログラムが予期せず終了します。