我在Linux機器上運行使用subprocess.check_output(),因爲它遵循其創建一個子進程的Python腳本:如何殺死當父母死亡時用subprocess.check_output()創建的python子進程?
subprocess.check_output(["ls", "-l"], stderr=subprocess.STDOUT)
的問題是,即使父進程死亡,孩子仍在運行。 有什麼辦法可以殺死孩子的過程以及父母死亡?
我在Linux機器上運行使用subprocess.check_output(),因爲它遵循其創建一個子進程的Python腳本:如何殺死當父母死亡時用subprocess.check_output()創建的python子進程?
subprocess.check_output(["ls", "-l"], stderr=subprocess.STDOUT)
的問題是,即使父進程死亡,孩子仍在運行。 有什麼辦法可以殺死孩子的過程以及父母死亡?
你的問題是使用subprocess.check_output
- 你是正確的,使用的界面,你不能讓孩子PID。使用POPEN代替:
proc = subprocess.Popen(["ls", "-l"], stdout=PIPE, stderr=PIPE)
# Here you can get the PID
global child_pid
child_pid = proc.pid
# Now we can wait for the child to complete
(output, error) = proc.communicate()
if error:
print "error:", error
print "output:", output
要確保你殺了孩子退出:
import os
import signal
def kill_child():
if child_pid is None:
pass
else:
os.kill(child_pid, signal.SIGTERM)
import atexit
atexit.register(kill_child)
不知道的細節,但最好的方法仍然是用信號捕捉錯誤(甚至可能是所有錯誤)並終止其中的任何剩餘進程。
import signal
import sys
import subprocess
import os
def signal_handler(signal, frame):
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
a = subprocess.check_output(["ls", "-l"], stderr=subprocess.STDOUT)
while 1:
pass # Press Ctrl-C (breaks the application and is catched by signal_handler()
這只是一個小樣,你需要捕捉的不僅僅是SIGINT以上,但這個想法可能會得到你開始,你需要檢查生成的進程仍莫名其妙。
http://docs.python.org/2/library/os.html#os.kill http://docs.python.org/2/library/subprocess.html#subprocess.Popen.pid http://docs.python.org/2/library/subprocess.html#subprocess.Popen.kill
我建議重寫check_output
原因個性化的版本,我才意識到check_output實際上只是簡單調試等,因爲你不能在執行過程中進行交互這麼多吧..
from subprocess import Popen, PIPE, STDOUT
from time import sleep, time
def checkOutput(cmd):
a = Popen('ls -l', shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
print(a.pid)
start = time()
while a.poll() == None or time()-start <= 30: #30 sec grace period
sleep(0.25)
if a.poll() == None:
print('Still running, killing')
a.kill()
else:
print('exit code:',a.poll())
output = a.stdout.read()
a.stdout.close()
a.stdin.close()
return output
,做任何你想用它一樣,PE rhaps將活動執行存儲在一個臨時變量中,並在退出時用信號或其他方式來阻止主循環的錯誤/關閉。
最後,您仍然需要在主應用程序中捕捉終端以便安全地殺死任何孩子,最好的方法是使用try & except
或signal
。
是的,你可以通過兩種方法實現這一點。他們都要求您使用Popen
而不是check_output
。首先是一個簡單的方法,使用try..finally如下:
from contextlib import contextmanager
@contextmanager
def run_and_terminate_process(*args, **kwargs):
try:
p = subprocess.Popen(*args, **kwargs)
yield p
finally:
p.terminate() # send sigterm, or ...
p.kill() # send sigkill
def main():
with run_and_terminate_process(args) as running_proc:
# Your code here, such as running_proc.stdout.readline()
這會趕上SIGINT(鍵盤中斷)和SIGTERM,而不是SIGKILL(如果你用-9殺死你的腳本)。
另一種方法有點複雜,並且使用ctypes的prctl PR_SET_PDEATHSIG。一旦父母因任何原因退出(甚至是sigkill),系統會向孩子發送信號。
import signal
import ctypes
libc = ctypes.CDLL("libc.so.6")
def set_pdeathsig(sig = signal.SIGTERM):
def callable():
return libc.prctl(1, sig)
return callable
p = subprocess.Popen(args, preexec_fn = set_pdeathsig(signal.SIGTERM))
如果你需要的命令的輸出,你可以用'p.stdout.read()'或'p.stdout.readlines()' – micromoses
一號方法只是開始,*立即*殺死子,你應該加上'在'Popen()'調用之後的p.communicate()/ p.wait()'。 [第2方法僅適用於Linux的(http://www.evans.io/posts/killing-child-processes-on-parent-exit-prctl/) – jfs
@JF,你是對的,這是不明朗我的例子是程序的代碼應該在'finally'語句之前出現,並且正確地縮進了'try' ..我認爲它現在更清晰了。無論如何,這個問題並不清楚,如果父母可能會在孩子面前死去(除非被殺死),所以我不能認爲實際的命令是'ls',或者應該等待孩子(可能是某種服務器?)。至於你的第二個評論,這個問題指出該系統是Linux。 – micromoses
[這](http://stackoverflow.com/a/14128476/2235132)回答可能的幫助。 – devnull
使用check_output FCT的時候,因爲我沒有得到孩子進程的PID它並不能幫助我,所以我不能殺死它... – Clara
相關:如何讓家長退出後,子進程死掉? (http://stackoverflow.com/q/284325/4279)和[最好的方法殺死所有的子進程(http://stackoverflow.com/q/392022/4279) – jfs