pythonmultiprocessingsubprocessterminate

Cannot terminate or kill subprocess after building .exe with pyinstaller


Terminating the following subprocess in the ways I described below works great when executing the script with python. However, after using pyinstaller to build a .exe file, the blender process is not terminated.

bpy_script_path = os.path.join(main_dir, 'Packages', 'Scripts', 'BlenderRendering', 'bpy_script.py')
blender_command = [blender_executable, '--background','--python', bpy_script_path]

if os.name == 'nt':
    CREATE_NO_WINDOW = 0x08000000
    blender_process = subprocess.Popen(blender_command, creationflags = CREATE_NO_WINDOW)
else:
    blender_process = subprocess.Popen(blender_command)
            
while blender_process.poll() == None:
    try:
        msg = queue.get_nowait()
        if msg[0] == 'kill':
            #tried first
            blender_process.kill()
            blender_process.wait()
            
            #tried second
            blender_process.terminate()
            blender_process.wait()

            #tried third
            subprocess.call(['taskkill', '/F', '/T', '/PID', str(blender_process.pid)])
            
            queue.put(('kill successful', None, None))
            return False
    except:
        pass
    time.sleep(1)

The code snippet I provided is part of a script that is being run as a multiprocess. Therefore, the communication via queue. I want to terminate/kill the blender process, when the main application is being closed. As the main application waits for the 'kill successful' message upon closing, not being able to terminate the blender process leads to the main_window running in a loop waiting for the message of successful termination. I also tried using psutil, but that doesn't work neither. Not sure what to do at this point..

while blender_process.poll() == None:
    msg = None
    try:
        msg = queue.get_nowait()
    except:
        pass
    if msg:
        if msg[0] == 'kill':
            subprocess.call(['taskkill', '/F', '/T', '/PID', str(blender_process.pid)])
            queue.put(('kill successful', None, None))
            return False
    time.sleep(1)

Solution

  • All three solutions mentioned in the question are working perfectly fine for terminating a multiprocess. The problem was rather the communication between the different processes. As multiple processes accessed the multiprocessing queue at the same time without synchronization, some signals/messages did not reach their supposed destination. In this case especially the 'kill' message did not get through as another loop in the main process that checks the queue already received the message.The problem was resolved using two multiprocessing events (main_window_close & blender_terminated) instead of relying on the same queue that is also used for other communication:

    while blender_process.poll() == None:
        if main_window_close.is_set():
            blender_process.terminate()
            blender_process.wait()
            blender_terminated.set()
            return False
        time.sleep(1)