![](/img/trans.png)
[英]subprocess.communicate() hangs on Windows 8 if parent process creates some child
[英]Python subprocess.communicate hangs when parent leaves zombies
我正在嘗試使用Popen
創建一個子進程A
以及一個使用Popen.communicate
通信的線程。 主進程將使用具有指定超時的Thread.join
在線程上等待,並在超時到期后終止A
,這應該導致線程也死掉。
但是,當A
本身產生的子進程B
, C
和D
不同於拒絕死亡的A
不同進程組時,這似乎不起作用。 即使在A
已經死亡並標記為已失效之后,即使在主進程使用os.waitpid()
獲得A
以使其不再存在之后,該線程也拒絕與主線程連接。
只有在所有的孩子, B
, C
, D
被殺之后, Popen.communicate
終於回來了。
這個行為實際上是從模塊中預期的嗎? 在某些情況下,遞歸等待可能很有用,但它肯定不適合作為Popen.communicate
的默認行為。 如果這是預期的行為,有沒有辦法覆蓋它?
這是一個非常簡單的例子:
from subprocess import PIPE, Popen
from threading import Thread
import os
import time
import signal
DEVNULL = open(os.devnull, 'w')
proc = Popen(["/bin/bash"], stdin=PIPE, stdout=PIPE,
stderr=DEVNULL, start_new_session=True)
def thread_function():
print("Entering thread")
return proc.communicate(input=b"nohup sleep 100 &\nexit\n")
thread = Thread(target=thread_function)
thread.start()
time.sleep(1)
proc.kill()
while True:
thread.join(timeout=5)
if not thread.is_alive():
break
print("Thread still alive")
這是在Linux上。
我認為這來自於在Linux中編寫popen.communicate方法的一種相當自然的方式。 Proc.communicate()似乎讀取stdin文件描述符,當進程終止時它將返回EOF。 然后它等待獲取進程的退出代碼。
在您的示例中,sleep進程從bash進程繼承stdin文件描述符。 因此,當bash進程終止時,popen.communicate沒有在stdin管道上獲得EOF,因為睡眠仍然打開它。 解決此問題的最簡單方法是將通信線路更改為:
return proc.communicate(input=b"nohup sleep 100 >/dev/null&\nexit\n")
這會導致你的線程在bash死亡后立即結束...由於退出,而不是你的proc.kill,在這種情況下。 但是,如果使用exit語句或proc.kill調用,則在bash死后,sleep仍在運行。 如果你想殺死睡眠,我會用
os.killpg(proc.pid,15)
而不是proc.kill()。 殺死B,C和D的更一般的問題是,如果他們改變組是一個更復雜的問題。
附加數據:我找不到這種proc.communicate方法的官方文檔,但我忘記了最明顯的地方:-)我在這個答案的幫助下找到了它。 溝通文件說:
與流程交互:將數據發送到stdin。 從stdout和stderr讀取數據,直到達到文件結尾。 等待進程終止。
您在步驟2中遇到困難:讀取直到文件結束,因為睡眠會使管道保持打開狀態。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.