2016-09-14 4 views
0

Ich benutze Python, um ein C++ - Programm mit dem Unterprozessmodul aufzurufen. Da das Programm einige Zeit benötigt, möchte ich es mit Strg + C beenden können. Ich habe ein paar Fragen dazu auf StackOverflow gesehen, aber keine der Lösungen scheint für mich zu funktionieren.Beenden eines Subprozesses mit KeyboardInterrupt

Was ich möchte ist, dass der Unterprozess auf KeyboardInterrupt beendet wird. Dies ist der Code, den ich (ähnlich Vorschläge in anderen Fragen) haben:

import subprocess 

binary_path = '/path/to/binary' 
args = 'arguments' # arbitrary 

call_str = '{} {}'.format(binary_path, args) 

proc = subprocess.Popen(call_str) 

try: 
    proc.wait() 
except KeyboardInterrupt: 
    proc.terminate() 

Allerdings, wenn ich dies ausführen, wird der Code hing für den Prozess wartet bis zu beenden und registriert nie die KeyboardInterrupt. Ich habe folgend auch versucht:

import subprocess 
import time 

binary_path = '/path/to/binary' 
args = 'arguments' # arbitrary 

call_str = '{} {}'.format(binary_path, args) 

proc = subprocess.Popen(call_str) 
time.sleep(5) 
proc.terminate() 

Diese Code-Schnipsel funktioniert gut an das Programm beendet wird, so dass es nicht das eigentliche Signal ist, dass das ist das Problem zu beenden gesendet werden wird.

Wie kann ich den Code ändern, damit der Unterprozess auf KeyboardInterrupt beendet werden kann?

Ich verwende Python 2.7 und Windows 7 64-Bit. Danke im Voraus!

Einige verwandte Fragen, die ich versucht:

Python sub process Ctrl+C

Kill subprocess.call after KeyboardInterrupt

kill subprocess when python process is killed?

+0

Warum fangen Sie nicht das Signal ctrl-c in Ihrem Hauptprogramm und verwenden Sie das, um 'proc.terminate()' aufzurufen? – CoconutBandit

+0

In Python 3 könnten Sie '_winapi.WaitForMultipleObjects ([proc._handle], False, -1)' verwenden. Für den Hauptthread und wenn das wait-all-Flag false ist, schließt diese Wartezeit automatisch das "SIGINT" -Ereignis von Python ein. In 2.x müssten Sie dies von Grund auf mit Ctypes oder PyWin32 implementieren. – eryksun

+0

@eryksun Danke für den Vorschlag.Es gibt ein Modul namens win32event, das eine ähnliche Funktion hat und für Python 2 importiert werden kann, aber ich habe 'win32event.WaitForMultipleObjects ([proc._handle], False, -1)' versucht und es hat keinen Unterschied gemacht. – limi44

Antwort

2

Ich habe einen Weg gefunden, dies zu tun, ähnlich der Antwort von Jean-Francois mit der Schleife, aber ohne die vielen Threads. Der Schlüssel ist, Popen.poll() zu verwenden, um festzustellen, ob der Subprozess beendet wurde (wird None zurückgeben, wenn er noch läuft).

import subprocess 
import time 

binary_path = '/path/to/binary' 
args = 'arguments' # arbitrary 

call_str = '{} {}'.format(binary_path, args) 

proc = subprocess.Popen(call_str) 

try: 
    while proc.poll() is None: 
     time.sleep(0.1) 

except KeyboardInterrupt: 
    proc.terminate() 
    raise 

Ich fügte hinzu, eine zusätzliche Erhöhung nach KeyboardInterrupt so das Python-Programm auch neben dem subprocess unterbrochen wird.

BEARBEITEN: Geänderter Durchlauf zu time.sleep (0.1) gemäß eryksuns Kommentar, um CPU-Verbrauch zu verringern.

+1

'time.sleep (.1)' ist unterbrechbar. Wenn Sie es anstelle von "pass" verwenden, sollte die CPU-Auslastung reduziert werden. – eryksun

1

Mein hässlich, aber erfolgreichen Versuch unter Windows:

import subprocess 
import threading 

import time 

binary_path = 'notepad' 
args = 'foo.txt' # arbitrary 

proc = None 
done = False 

def s(): 
    call_str = '{} {}'.format(binary_path, args) 
    global done 
    global proc 
    proc = subprocess.Popen(call_str,stdout=subprocess.PIPE) 
    proc.wait() 
    done = True 


t = threading.Thread(target=s) 
t.start() 


try: 
    while not done: 
     time.sleep(0.1) 

except KeyboardInterrupt: 
    print("terminated") 
    proc.terminate() 

Crea einen Thread, in dem der Subprozess ausgeführt wird. Exportieren Sie die proc Variable.

Dann warten Sie in einer nicht aktiven Schleife für immer. Wenn STRG + C gedrückt wird, wird die Ausnahme ausgelöst. Die Kommunikation zwischen Prozessen (z. B. proc.wait()) steht ansonsten im Konflikt mit der CTRL + C-Behandlung. Wenn in einem Thread ausgeführt wird, kein solches Problem.

Hinweis: Ich habe versucht, diese Zeitschleife mit threading.lock() zu vermeiden, stolperte aber auf der gleichen CTRL + C ignorieren.

Verwandte Themen