I am facing the following problem and can't solve it.
- A runs B as
multiprocessing.Process()
- B runs C as
subprocess.run()
- A terminates B by
multiprocessing.Process.terminate()
- 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.