Python: comment empêcher les sous-processus de recevoir CTRL - C / Control - C / SIGINT
Je travaille actuellement sur un wrapper pour un serveur dédié s'exécutant dans le shell. Le wrapper génère le processus serveur via le sous-processus et observe et réagit à sa sortie.
Le serveur dédié doit recevoir explicitement une commande pour fermer gracieusement. Ainsi, CTRL-C ne doit pas atteindre le processus serveur.
Si je capture L'exception KeyboardInterrupt ou remplace le gestionnaire SIGINT en python, le processus serveur reçoit toujours le CTRL-C et s'arrête immédiatement.
Donc ma question est: Comment empêcher les sous-processus de recevoir CTRL-C / Control-C / SIGINT?
4 réponses
Quelqu'un dans le canal IRC #python (Freenode) m'a aidé en pointant le paramètre preexec_fn du sous-processus .Popen(...):
Si preexec_fn {[3] } est défini sur un appelable objet, cet objet sera appelée dans le processus enfant juste avant l' l'enfant est exécuté. (Unix uniquement)
Ainsi, le code suivant résout le problème (UNIX uniquement):
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
)
Remarque:, Le signal est en fait pas empêché d'atteindre le sous-processus. Au lieu de cela, le preexec_fn ci-dessus écrase le gestionnaire par défaut du signal afin que le signal soit ignoré. Ainsi, Cette solution Peut Ne pas fonctionner si le sous-processus écrase à nouveau le gestionnaire SIGINT.
Une autre note: Cette solution fonctionne pour toutes sortes de sous-processus, c'est-à-dire qu'elle n'est pas limitée aux sous-processus écrits en Python. Par exemple, le serveur dédié pour lequel j'écris mon wrapper est en fait écrit en Java.
Combinant certaines des autres réponses qui feront l'affaire-aucun signal envoyé à l'application principale ne sera transmis au sous-processus.
import os
from subprocess import Popen
def preexec(): # Don't forward signals.
os.setpgrp()
Popen('whatever', preexec_fn = preexec)
Essayez de définir SIGINT sur ignoré avant de générer le sous-processus (réinitialisez-le au comportement par défaut par la suite).
Si cela ne fonctionne pas, vous devrez lire job control et apprendre à placer un processus dans son propre groupe de processus d'arrière-plan, de sorte que ^C ne provoque même pas l'envoi du signal par le noyau. (Peut ne pas être possible en Python sans écrire des aides C.)
Voir aussi cette ancienne question.
Vous pouvez faire quelque chose comme cela pour le faire fonctionner sous windows et 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)