web-dev-qa-db-ja.com

Python:サブプロセスがCTRL-C / Control-C / SIGINTを受け取らないようにする方法

私は現在、シェルで実行されている専用サーバーのラッパーに取り組んでいます。ラッパーはサブプロセスを介してサーバープロセスを生成し、その出力を監視して反応します。

専用サーバーには、正常にシャットダウンするコマンドを明示的に指定する必要があります。したがって、CTRL-Cはサーバープロセスに到達してはなりません。

KeyboardInterrupt例外をキャプチャするか、PythonでSIGINTハンドラーを上書きしても、サーバープロセスは引き続きCTRL-Cを受け取り、すぐに停止します。

だから私の質問は:サブプロセスがCTRL-C/Control-C/SIGINTを受け取らないようにする方法は?

40
robert

#python IRC-Channel(Freenode)の誰かが、subprocess.Popen(...)preexec_fnパラメーターを指摘してくれました。

preexec_fnが呼び出し可能オブジェクトに設定されている場合、このオブジェクトは、子が実行される直前に子プロセスで呼び出されます。 (Unixのみ)

したがって、次のコードは問題を解決します(UNIXのみ)。

import subprocess
import signal

def preexec_function():
    # Ignore the SIGINT signal by setting the handler to the standard
    # signal handler SIG_IGN.
    signal.signal(signal.SIGINT, signal.SIG_IGN)

my_process = subprocess.Popen(
    ["my_executable"],
    preexec_fn = preexec_function
)

注:シグナルは実際にはサブプロセスに到達することを妨げられていません。代わりに、上記のpreexec_fnは、シグナルのデフォルトハンドラーを上書きして、シグナルが無視されるようにします。したがって、このソリューションmayは、サブプロセスが[〜#〜] sigint [〜#〜]ハンドラーを再度上書きすると機能しません。

別の注意:このソリューションは、あらゆる種類のサブプロセスで機能します。つまり、Pythonで記述されたサブプロセスにも制限されません。たとえば、ラッパーを作成している専用サーバーは、実際にはJavaで作成されています。

41
robert

トリックを実行する他のいくつかの回答を組み合わせると、メインアプリに送信されたシグナルはサブプロセスに転送されません。

import os
from subprocess import Popen

def preexec(): # Don't forward signals.
    os.setpgrp()

Popen('whatever', preexec_fn = preexec)
24
Marek Sapota

あなたはそれをウィンドウズとUNIXで動作させるためにこのようなことをすることができます:

import subprocess
import sys

def pre_exec():
    # To ignore CTRL+C signal in the new process
    signal.signal(signal.SIGINT, signal.SIG_IGN)

if sys.platform.startswith('win'):
    #https://msdn.Microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
    #CREATE_NEW_PROCESS_GROUP=0x00000200 -> If this flag is specified, CTRL+C signals will be disabled
    my_sub_process=subprocess.Popen(["executable"], creationflags=0x00000200)
else:
    my_sub_process=subprocess.Popen(["executable"], preexec_fn = pre_exec)
3
jpastell

サブプロセスを生成する前に、SIGINTをignoredに設定してみてください(後でデフォルトの動作にリセットしてください)。

それがうまくいかない場合は、 ジョブ制御 を読んで、プロセスを独自のバックグラウンドプロセスグループに入れる方法を学ぶ必要があります。 ^C そもそもカーネルにシグナルを送信させることすらありません。 (Python Cヘルパーを記述しないと不可能な場合があります。)

この古い質問 も参照してください。

1
zwol