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?

35
demandé sur robert 2011-02-18 22:39:38

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.

34
répondu robert 2013-10-14 14:30:51

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)
21
répondu Marek Sapota 2011-03-27 03:16:56

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.

1
répondu zwol 2017-05-23 12:10:24

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)
1
répondu jpastell 2016-08-26 21:02:19