Home > database >  How to close Subprocess that runs other Subprocess on Windows?
How to close Subprocess that runs other Subprocess on Windows?

Time:06-15

I am facing the following problem and can't solve it.

  1. A runs B as multiprocessing.Process()
  2. B runs C as subprocess.run()
  3. A terminates B by multiprocessing.Process.terminate()
  4. Expected: B and C are terminated
    Result: B is terminated and C runs in background

Important additional information

  • A, B, C are programs
  • A is my program that I develop
  • B, C are external programs not developed by me and I have no control of
  • Solution must work on Windows

Question Does anyone have any solution or know if it isn't possible?

Following code describes my problem on example:

# main.py - Process A
# Runs Process B
import multiprocessing
from Manager import manager
from time import sleep

def main():
    proc = multiprocessing.Process(target=manager)

    proc.start()
    print("[MAIN] Process going sleep")
    sleep(3)
    print("[MAIN] Process is awake now. Beginning to terminate")
    proc.terminate()
    proc.join()
    print("[MAIN] Process Manager terminated.")

if __name__ == "__main__":
    main()
# Manager.py - Process B
# Cannot change any code
# Runs process C
import subprocess

def manager():
    print("[MANAGER] START")
    subprocess.run(["python", "sleepery.py"])
    print("[MANAGER] Terminated")
# sleepery.py - Process C
# Cannot change any code
from time import sleep

def sleeper():
    """This process prints info every two seconds for 8"""
    for _ in range(4):
        sleep(2)
        print(f"[SLEEPER] prints!")
    print("[SLEEPER] ends")

if __name__ == "__main__":
    sleeper()

OUTPUT

[MAIN] Process going sleep
[MANAGER] START
[SLEEPER] prints!
[MAIN] Process is awake now. Beginning to terminate
[MAIN] Process Manager terminated.
[SLEEPER] prints! 
[SLEEPER] prints!
[SLEEPER] prints!
[SLEEPER] ends

WANTED OUTPUT

[MAIN] Process going sleep
[MANAGER] START
[SLEEPER] prints!
[MAIN] Process is awake now. Beginning to terminate
[MAIN] Process Manager terminated.

My research
The only thing that works is to kill all python processes by taskkill
But it isn't exactly graceful

CodePudding user response:

Use a Job object, this allows you to group all child processes in this job and kill them all in a single step.

CodePudding user response:

Anders's answer goes right into the point.
Here is refactored main.py to use Job Objects

# main.py - Process A
# Runs Process B
import multiprocessing

import win32api
from Manager import manager
from time import sleep
import time
import win32job
import win32con

def main():
    jobHandle = win32job.CreateJobObject(None, "")
    proc = multiprocessing.Process(target=manager)
    proc.start()
    # Get handle to process and assign process to job object
    handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, proc.pid)
    win32job.AssignProcessToJobObject(jobHandle, handle)
    print("[MAIN] Process going sleep")
    sleep(3)
    print("[MAIN] Process is awake now. Beginning to terminate")
    win32job.TerminateJobObject(jobHandle, 0)
    print("[MAIN] Process Manager and his kids terminated.")

if __name__ == "__main__":
    main()

Then output:

> python .\main.py
[MAIN] Process going sleep
[MANAGER] START
[SLEEPER] prints!
[MAIN] Process is awake now. Beginning to terminate
[MAIN] Process Manager and his kids terminated.
  • Related