18.8. signal —非同期イベントのハンドラーを設定します—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.6/library/signal
移動先:案内検索

18.8。 信号 —非同期イベントのハンドラーを設定します


このモジュールは、Pythonでシグナルハンドラーを使用するメカニズムを提供します。

18.8.1。 一般的なルール

signal.signal()関数を使用すると、シグナルを受信したときに実行されるカスタムハンドラーを定義できます。 少数のデフォルトハンドラーがインストールされています。SIGPIPEは無視され(したがって、パイプとソケットの書き込みエラーは通常のPython例外として報告されます)、SIGINTKeyboardInterrupt に変換されます。 ] 例外。

特定のシグナルのハンドラーは、一度設定されると、明示的にリセットされるまでインストールされたままになります(Pythonは、基になる実装に関係なくBSDスタイルのインターフェイスをエミュレートします)。ただし、基になる実装に続くSIGCHLDのハンドラーは例外です。 。

18.8.1.1。 Pythonシグナルハンドラーの実行

Pythonシグナルハンドラーは、低レベル(C)シグナルハンドラー内では実行されません。 代わりに、低レベルのシグナルハンドラーは、仮想マシンに対応するPythonシグナルハンドラーを後の時点(たとえば、次のバイトコード命令)で実行するように指示するフラグを設定します。 これは結果をもたらします:

  • SIGFPESIGSEGVのような、Cコードの無効な操作によって引き起こされる同期エラーをキャッチすることはほとんど意味がありません。 PythonはシグナルハンドラーからCコードに戻ります。これにより、同じシグナルが再び発生する可能性があり、Pythonが明らかにハングします。 Python 3.3以降では、 faulthandler モジュールを使用して同期エラーを報告できます。
  • 純粋にCで実装された長時間実行の計算(大量のテキストでの正規表現マッチングなど)は、受信した信号に関係なく、任意の時間中断することなく実行できます。 計算が終了すると、Pythonシグナルハンドラーが呼び出されます。


18.8.1.2。 シグナルとスレッド

Pythonシグナルハンドラーは、シグナルが別のスレッドで受信された場合でも、常にメインのPythonスレッドで実行されます。 これは、シグナルをスレッド間通信の手段として使用できないことを意味します。 代わりに、 threading モジュールの同期プリミティブを使用できます。

さらに、メインスレッドのみが新しいシグナルハンドラーを設定できます。


18.8.2。 モジュールの内容

バージョン3.5で変更:シグナル(SIG *)、ハンドラー( SIG_DFLSIG_IGN )、およびsigmask( SIG_BLOCKSIG_UNBLOCKSIG_SETMASK )に関連する以下の定数は、列挙型に変換されました。 getsignal()pthread_sigmask()sigpending()、および sigwait()関数は、人間が読める形式の列挙型[X139X ]。


signal モジュールで定義されている変数は次のとおりです。

signal.SIG_DFL
これは、2つの標準的な信号処理オプションの1つです。 シグナルのデフォルト機能を実行するだけです。 たとえば、ほとんどのシステムでは、SIGQUITのデフォルトのアクションはコアをダンプして終了することですが、SIGCHLDのデフォルトのアクションは単にそれを無視することです。
signal.SIG_IGN
これは別の標準的なシグナルハンドラーであり、指定されたシグナルを単に無視します。
SIG*
すべての信号番号はシンボリックに定義されています。 たとえば、ハングアップ信号はsignal.SIGHUPとして定義されます。 変数名は、<signal.h>にあるように、Cプログラムで使用される名前と同じです。 'signal()'のUnixマニュアルページには、既存のシグナルがリストされています(一部のシステムでは、これは signal(2)であり、他のシステムでは、リストは signal(7)にあります。 )。 すべてのシステムが同じ信号名のセットを定義しているわけではないことに注意してください。 システムによって定義された名前のみがこのモジュールによって定義されます。
signal.CTRL_C_EVENT

Ctrl + C キーストロークイベントに対応する信号。 この信号は、 os.kill()でのみ使用できます。

可用性:Windows。

バージョン3.2の新機能。

signal.CTRL_BREAK_EVENT

Ctrl + Break キーストロークイベントに対応する信号。 この信号は、 os.kill()でのみ使用できます。

可用性:Windows。

バージョン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 のサブタイプです。

バージョン3.3の新機能:このエラーは、以前は IOError のサブタイプでしたが、現在は OSError のエイリアスになっています。

signal モジュールは、次の機能を定義します。

signal.alarm(time)
time がゼロ以外の場合、この関数はSIGALRM信号が time 秒でプロセスに送信されることを要求します。 以前にスケジュールされたアラームはキャンセルされます(一度にスケジュールできるアラームは1つだけです)。 戻り値は、以前に設定されたアラームが配信されるまでの秒数です。 time がゼロの場合、アラームはスケジュールされず、スケジュールされたアラームはキャンセルされます。 戻り値がゼロの場合、現在アラームはスケジュールされていません。 (Unixのマニュアルページ alarm(2)を参照してください。)可用性:Unix。
signal.getsignal(signalnum)
シグナル signalnum の現在のシグナルハンドラーを返します。 戻り値は、呼び出し可能なPythonオブジェクト、または特別な値 signal.SIG_IGNsignal.SIG_DFL 、または None のいずれかです。 ここで、 signal.SIG_IGN は信号が以前に無視されたことを意味し、 signal.SIG_DFL は信号を処理するデフォルトの方法が以前に使用されていたことを意味し、Noneは以前のシグナルハンドラーがPythonからインストールされていないこと。
signal.pause()

シグナルが受信されるまでプロセスをスリープ状態にします。 次に、適切なハンドラーが呼び出されます。 何も返しません。 Windowsではありません。 (Unixのマニュアルページ signal(2)を参照してください。)

sigwait()sigwaitinfo()sigtimedwait()、および sigpending()も参照してください。

signal.pthread_kill(thread_id, signalnum)

シグナル signalnum を、呼び出し元と同じプロセス内の別のスレッドであるスレッド thread_id に送信します。 ターゲットスレッドは、任意のコード(Pythonかどうか)を実行できます。 ただし、ターゲットスレッドがPythonインタープリターを実行している場合、Pythonシグナルハンドラーはメインスレッドによって実行されます。 したがって、特定のPythonスレッドにシグナルを送信する唯一のポイントは、実行中のシステムコールを InterruptedError で強制的に失敗させることです。

threading.get_ident()または threading.Thread オブジェクトの ident 属性を使用して、 thread_id の適切な値を取得します。

signalnum が0の場合、シグナルは送信されませんが、エラーチェックは引き続き実行されます。 これを使用して、ターゲットスレッドがまだ実行されているかどうかを確認できます。

可用性:Unix(詳細については、manページ pthread_kill(3)を参照してください)。

os.kill()も参照してください。

バージョン3.3の新機能。

signal.pthread_sigmask(how, mask)

呼び出し元のスレッドのシグナルマスクをフェッチおよび/または変更します。 シグナルマスクは、発信者に対して現在配信がブロックされているシグナルのセットです。 古い信号マスクを信号のセットとして返します。

呼び出しの動作は、次のように how の値に依存します。

  • SIG_BLOCK :ブロックされた信号のセットは、現在のセットと mask 引数の和集合です。

  • SIG_UNBLOCKマスクの信号は、現在ブロックされている信号のセットから削除されます。 ブロックされていない信号のブロックを解除しようとしてもかまいません。

  • SIG_SETMASK :ブロックされた信号のセットは mask 引数に設定されます。

マスクは信号番号のセットです(例: {signal.SIGINTsignal.SIGTERM})。 すべての信号を含む完全なマスクには、range(1, signal.NSIG)を使用します。

たとえば、signal.pthread_sigmask(signal.SIG_BLOCK, [])は、呼び出し元のスレッドのシグナルマスクを読み取ります。

可用性:Unix。 詳細については、manページ sigprocmask(3)および pthread_sigmask(3)を参照してください。

pause()sigpending()、および sigwait()も参照してください。

バージョン3.3の新機能。

signal.setitimer(which, seconds[, interval])

で指定されたインターバルタイマー( signal.ITIMER_REALsignal.ITIMER_VIRTUALsignal.ITIMER_PROF のいずれか)をで指定しての後に起動するように設定します。 X168X]秒(フロートが受け入れられ、 alarm()とは異なります)、その後は間隔秒ごと。 で指定されたインターバルタイマーは、秒をゼロに設定することでクリアできます。

インターバルタイマーが作動すると、信号がプロセスに送信されます。 送信される信号は、使用されているタイマーによって異なります。 signal.ITIMER_REALSIGALRMを配信し、 signal.ITIMER_VIRTUALSIGVTALRMを送信し、 signal.ITIMER_PROFSIGPROF

古い値はタプルとして返されます:(遅延、間隔)。

無効なインターバルタイマーを通過させようとすると、 ItimerError が発生します。 可用性:Unix。

signal.getitimer(which)
which で指定されたインターバルタイマーの現在値を返します。 可用性:Unix。
signal.set_wakeup_fd(fd)

ウェイクアップファイル記述子を fd に設定します。 信号を受信すると、信号番号が1バイトとしてfdに書き込まれます。 これをライブラリで使用して、ポーリングまたは選択呼び出しをウェイクアップし、信号を完全に処理できるようにすることができます。

古いウェイクアップfdが返されます(またはファイル記述子ウェイクアップが有効になっていない場合は-1)。 fd が-1の場合、ファイル記述子のウェイクアップは無効になります。 -1でない場合、 fd は非ブロッキングである必要があります。 ポーリングを呼び出す前、または再度選択する前に、 fd からバイトを削除するのはライブラリの責任です。

たとえば、struct.unpack('%uB' % len(data), data)を使用して、信号番号リストをデコードします。

スレッドが有効になっている場合、この関数はメインスレッドからのみ呼び出すことができます。 他のスレッドから呼び出そうとすると、 ValueError 例外が発生します。

バージョン3.5で変更: Windowsでは、この関数はソケットハンドルもサポートするようになりました。

signal.siginterrupt(signalnum, flag)

システムコールの再起動動作の変更:フラグFalse の場合、信号 signalnum によって中断されるとシステムコールが再開されます。それ以外の場合、システムコールは中断されます。 何も返しません。 可用性:Unix(詳細については、manページ siginterrupt(3)を参照してください)。

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()は、SIGABRTSIGFPESIGILLSIGINT、 [X102Xでのみ呼び出すことができます。 ]、SIGTERM、またはSIGBREAK。 それ以外の場合は、 ValueError が発生します。 すべてのシステムが同じ信号名のセットを定義しているわけではないことに注意してください。 信号名がSIG*モジュールレベル定数として定義されていない場合、 AttributeError が発生します。

signal.sigpending()

呼び出しスレッドへの配信が保留されている一連のシグナル(つまり、ブロック中に発生したシグナル)を調べます。 保留中のシグナルのセットを返します。

可用性:Unix(詳細については、manページ sigpending(2)を参照してください)。

pause()pthread_sigmask()、および sigwait()も参照してください。

バージョン3.3の新機能。

signal.sigwait(sigset)

シグナルセット sigset で指定されたシグナルの1つが配信されるまで、呼び出しスレッドの実行を一時停止します。 この関数はシグナルを受け入れ(シグナルの保留リストから削除し)、シグナル番号を返します。

可用性:Unix(詳細については、manページ sigwait(3)を参照してください)。

pause()pthread_sigmask()sigpending()sigwaitinfo()sigtimedwait()も参照してください。 ]。

バージョン3.3の新機能。

signal.sigwaitinfo(sigset)

シグナルセット sigset で指定されたシグナルの1つが配信されるまで、呼び出しスレッドの実行を一時停止します。 この関数はシグナルを受け入れ、保留中のシグナルのリストからそれを削除します。 sigset のシグナルの1つが呼び出し元のスレッドに対してすでに保留中の場合、関数はそのシグナルに関する情報をすぐに返します。 配信された信号に対してシグナルハンドラーは呼び出されません。 この関数は、 sigset にない信号によって中断された場合、 InterruptedError を発生させます。

戻り値は、siginfo_t構造に含まれるデータを表すオブジェクトです。つまり、si_signosi_codesi_errnosi_pidsi_uidsi_statussi_band

可用性:Unix(詳細については、manページ sigwaitinfo(2)を参照してください)。

pause()sigwait()、および sigtimedwait()も参照してください。

バージョン3.3の新機能。

バージョン3.5で変更: sigset にないシグナルによって中断され、シグナルハンドラーが例外を発生させない場合、関数が再試行されるようになりました( を参照)。理論的根拠についてはPEP475 )。

signal.sigtimedwait(sigset, timeout)

sigwaitinfo()と同様ですが、タイムアウトを指定する追加の timeout 引数を取ります。 timeout0として指定されている場合、ポーリングが実行されます。 タイムアウトが発生した場合、 None を返します。

可用性:Unix(詳細については、manページ sigtimedwait(2)を参照してください)。

pause()sigwait()、および sigwaitinfo()も参照してください。

バージョン3.3の新機能。

バージョン3.5で変更: sigset にないシグナルによって中断され、シグナルハンドラーが例外を発生させない場合、関数は再計算された timeout で再試行されるようになりました(理論的根拠については、 PEP 475 を参照してください)。


18.8.3。 例

これが最小限のサンプルプログラムです。 alarm()関数を使用して、ファイルを開くのを待つ時間を制限します。 これは、ファイルがオンになっていない可能性のあるシリアルデバイス用である場合に役立ちます。これにより、通常、 os.open()が無期限にハングします。 解決策は、ファイルを開く前に5秒のアラームを設定することです。 操作に時間がかかりすぎると、アラーム信号が送信され、ハンドラーが例外を発生させます。

import signal, os

def handler(signum, frame):
    print('Signal handler called with signal', signum)
    raise OSError("Couldn't open device!")

# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)

# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0)          # Disable the alarm