18

I would like:

  1. Launch a new process (myexe.exe arg1) from my process (myexe.exe arg0)
  2. Retrieve the PID of this new process (os windows)
  3. when I kill my first entity (myexe.exe arg0) with the TaskManager Windows Command "End process tree", I need that the new one (myexe.exe arg1) will not be killed...

I've played with subprocess.Popen, os.exec, os.spawn, os.system... without success.

Another way to explain the problem: How to protect myexe.exe (arg1) if someone kills the "process tree" of the myexe.exe (arg0)?

EDIT: same question (without answer) HERE

EDIT: the following command do not guarantee the Independence of the subprocess

subprocess.Popen(["myexe.exe",arg[1]],creationflags = DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,close_fds = True)
Community
  • 1
  • 1
baco
  • 443
  • 1
  • 5
  • 14
  • Have you any example code of what you've done so far? – sotapme Feb 10 '13 at 11:30
  • related: [Popen waiting for child process even when the immediate child has terminated](http://stackoverflow.com/questions/13243807/popen-waiting-for-child-process-even-when-the-immediate-child-has-terminated) – jfs Feb 10 '13 at 11:43
  • 1
    Possible duplicate of [Launch a totally independent process from Python](http://stackoverflow.com/questions/13592219/launch-a-totally-independent-process-from-python) – jtpereyda Feb 28 '17 at 03:21

4 Answers4

14

To start a child process that can continue to run after the parent process exits on Windows:

from subprocess import Popen, PIPE

CREATE_NEW_PROCESS_GROUP = 0x00000200
DETACHED_PROCESS = 0x00000008

p = Popen(["myexe.exe", "arg1"], stdin=PIPE, stdout=PIPE, stderr=PIPE,
          creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP)
print(p.pid)

Windows process creation flags are here

A more portable version is here.

rstackhouse
  • 2,238
  • 24
  • 28
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • 1
    nice try! But when I kill the "myexe.exe" (arg0) through "End process tree" taskmanager command of windows, both myexe.exe were killed ! If I've done the same command on the "myexe.exe" (arg1) only this entity will be killed... – baco Feb 10 '13 at 13:31
  • @baco: Use the option that kills only one process instead of "process tree". – jfs Feb 10 '13 at 13:38
  • Probably the process tree is traversed in both directions. – nikola Feb 10 '13 at 13:39
  • @JF Sebastian: that the question => how to protect myexe.exe (arg1) if someone kill the "process tree" of the myexe.exe (arg0) (the solution seems to use os.startfile but I can't use args!) – baco Feb 10 '13 at 14:17
  • @baco: try to start an intermediate process `X` from `arg0` that does nothing but just starts `arg1` and exits immediately (you can read the pid of the grandchild in `arg0` via `X`'s stdout). – jfs Feb 10 '13 at 14:28
  • @ J.F. Sebastian: my question have no easy answering (see my EDIT) – baco Feb 10 '13 at 14:45
  • @baco: Try the command from my answer as is (without `close_fds`). Have you tried the double-fork variant from my previous comment? – jfs Feb 10 '13 at 15:53
  • @ J.F. Sebastian: No even without "close_fds" or a double fork, I can kill both myexe.exe... – baco Feb 10 '13 at 16:29
  • @ J.F. Sebastian: I think double fork does not work because of windows os, dont you? – baco Feb 10 '13 at 17:44
  • @baco: I should have put "double fork" in quotes. I just meant using Popen twice (create child, create grandchild, exit child). Though it might be pointless. – jfs Feb 10 '13 at 17:59
  • In case anyone finds it helpful, in my case executing a batch script I used **1.** `DETACHED_PROCESS = 0x00000008`, **2.** `Cmd = ["cmd.exe", "/C", RunScript, arg1, arg2, arg3]`, and then **3.** `subprocess.Popen(Cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, creationflags=DETACHED_PROCESS)` seems to work as expected when simply executing a batch script with commands and passing in arguments. I got odd results such as `findstr` commands opening a new window per each command used in the batch script with `subprocess.Popen()` until I used this syntax then it worked. – Bitcoin Murderous Maniac Apr 30 '18 at 23:35
  • 1
    The windows process creation flags are (now) also available as `subprocess` [windows constants](https://docs.python.org/3/library/subprocess.html#windows-constants). – djvg Nov 17 '21 at 14:36
1

I did similar a couple of years ago on windows and my issue was wanting to kill the child process.

I presume you can run the subprocess using pid = Popen(["/bin/mycmd", "myarg"]).pid so I'm unsure what the real issue is, so I'm guessing it's when you kill the main process.

IIRC it was something to do with the flags.

I can't prove it as I'm not running Windows.

subprocess.CREATE_NEW_CONSOLE
The new process has a new console, instead of inheriting its parent’s console (the default).

This flag is always set when Popen is created with shell=True.

subprocess.CREATE_NEW_PROCESS_GROUP
A Popen creationflags parameter to specify that a new process group will be created. This flag is necessary for using os.kill() on the subprocess.

This flag is ignored if CREATE_NEW_CONSOLE is specified.
sotapme
  • 4,695
  • 2
  • 19
  • 20
1

So if I understand you right the code should go like this:

from subprocess import Popen, PIPE
script = "C:\myexe.exe"
param = "-help"
DETACHED_PROCESS = 0x00000008
CREATE_NEW_PROCESS_GROUP = 0x00000200
pid = Popen([script, param], shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE,
            creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP)

At least I tried this one and worked for me.

1

I have tried all the proposed solutions for Windows 10 but all of them still open the new process as part of the original processes' process tree (either directly below the main process or with a cmd shell in between). The only solution that is working for me is to create a fully independent process/fork using the cmd.exe's start command:

import subprocess
subprocess.Popen(["cmd.exe", "/C", "start notepad"])

This is actually even easier as it requires no mangling with stdin/out parameters. Obviously, since it is completely independent, you cannot communicate with it. But you can use psutil to retrieve it's PID to at least monitor or close it, if necessary:

import psutil
for process in psutil.process_iter():
    if process.name() == 'notepad.exe':
        print(process.pid)
Robert
  • 1,357
  • 15
  • 26