Попен, ожидающий детского процесса, даже когда ближайший ребенок прекратил

Я работаю с Python 2.7 на Windows 8/XP.

У меня есть программа A, которая запускает другую программу B, используя следующий код:

p = Popen(["B"], stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
return

B запускает пакет script C. C - длинный script, и я хочу, чтобы B выходил, даже если C не закончил. Я сделал это, используя следующий код (в B):

p = Popen(["C"])
return

Когда я запускаю B, он работает так, как ожидалось. Однако, когда я запускал A, я ожидал, что он выйдет, когда B выйдет. Но A ждет, пока C не выйдет, хотя B уже вышел. Любые идеи о том, что происходит и какие возможные решения могут быть?

К сожалению, очевидное решение об изменении A, чтобы выглядеть как B, не является вариантом.

Вот пример функционального примера для иллюстрации этой проблемы: https://www.dropbox.com/s/cbplwjpmydogvu2/popen.zip?dl=1

Приветствуется любой ввод.

Ответ 1

Вы можете предоставить аналог start_new_session для подпроцесса C:

#!/usr/bin/env python
import os
import sys
import platform
from subprocess import Popen, PIPE

# set system/version dependent "start_new_session" analogs
kwargs = {}
if platform.system() == 'Windows':
    # from msdn [1]
    CREATE_NEW_PROCESS_GROUP = 0x00000200  # note: could get it from subprocess
    DETACHED_PROCESS = 0x00000008          # 0x8 | 0x200 == 0x208
    kwargs.update(creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP)  
elif sys.version_info < (3, 2):  # assume posix
    kwargs.update(preexec_fn=os.setsid)
else:  # Python 3.2+ and Unix
    kwargs.update(start_new_session=True)

p = Popen(["C"], stdin=PIPE, stdout=PIPE, stderr=PIPE, **kwargs)
assert not p.poll()

[1]: Флаги создания процесса для CreateProcess()

Ответ 2

Вот фрагмент кода, адаптированный из ответа Себастьяна, и этот ответ:

#!/usr/bin/env python
import os
import sys
import platform
from subprocess import Popen, PIPE

# set system/version dependent "start_new_session" analogs
kwargs = {}
if platform.system() == 'Windows':
    # from msdn [1]
    CREATE_NEW_PROCESS_GROUP = 0x00000200  # note: could get it from subprocess
    DETACHED_PROCESS = 0x00000008          # 0x8 | 0x200 == 0x208
    kwargs.update(creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP, close_fds=True)  
elif sys.version_info < (3, 2):  # assume posix
    kwargs.update(preexec_fn=os.setsid)
else:  # Python 3.2+ and Unix
    kwargs.update(start_new_session=True)

p = Popen(["C"], stdin=PIPE, stdout=PIPE, stderr=PIPE, **kwargs)
assert not p.poll()

Я тестировал его только в Windows.