4

On Windows boxes, I have a number of scenarios where a parent process will start a child process. For various reasons - the parent process may want to abort the child process but (and this is important) allow it to clean up - ie run a finally clause:

try:
  res = bookResource()
  doStuff(res)
finally:
  cleanupResource(res)

(These things may be embedded in contexts like the closer - and generally are around hardware locking/database state)

The problem is that I'm unable to find a way to signal the child in Windows (as I would in a Linux environment) so it would run the clean up before terminating. I think this requires making the child process raise an exception somehow (as the Ctrl-C would).

Things I've tried:

  • os.kill
  • os.signal
  • subprocess.Popen with creationFlags and using ctypes.windll.kernel32.GenerateConsoleCtrlEvent(1, p.pid) abrt signal. This requires a signal trap and inelegant loop to stop it immediately aborting.
  • ctypes.windll.kernel32.GenerateConsoleCtrlEvent(0, p.pid)- ctrl-c event - did nothing.

Has anyone got a surefire way of doing this, so that the child process can clean up?

Danny Staple
  • 7,101
  • 4
  • 43
  • 56
  • put a text file in the system that the children periodically check to see if they should exit.. would be pretty surefire ... but there is probably a better way or open some kind of socket server to listen on – Joran Beasley Nov 01 '13 at 17:05
  • are you already using `signal()` to register a signal handler for the kill -HUP? – Corley Brigman Nov 01 '13 at 17:54
  • 1
    btw, this from the right: http://stackoverflow.com/questions/5033277/how-to-achieve-desired-results-when-using-the-subprocees-popen-send-signalctrl?rq=1 is almost exactly what you need... – Corley Brigman Nov 01 '13 at 17:56
  • ahh your right ... my bad ... reading comprehension fail ... edit that said alot of it probably could be applied here as well – Joran Beasley Nov 01 '13 at 21:32
  • The signal trap and inelegant loop is solved if you can raise exceptions from within the trap - I didn't think that catcher would actually get the exception on account of the signal coming from somewhere else. I'll try this out on the target systems on Monday. – Danny Staple Nov 02 '13 at 13:26
  • *I think this requires making the child process raise an exception somehow* In case it doesn't the title of the question should actually make it clear what you would like to achieve (gracefully terminate subprocess). – Piotr Dobrogost Nov 02 '13 at 23:03
  • I've made it clearer. That the finally clauses run is critical to this being more useful than an existing clunkier approach. – Danny Staple Nov 04 '13 at 16:25

1 Answers1

2

I was able to get the GenerateConsoleCtrlEvent working like this:

import time
import win32api
import win32con
from multiprocessing import Process


def foo():
    try:
        while True:
            print("Child process still working...")
            time.sleep(1)
    except KeyboardInterrupt:
        print "Child process: caught ctrl-c"

if __name__ == "__main__":
    p = Process(target=foo)
    p.start()
    time.sleep(2)

    print "sending ctrl c..."
    try:
        win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, 0)
        while p.is_alive():
            print("Child process is still alive.")
            time.sleep(1)
    except KeyboardInterrupt:
        print "Main process: caught ctrl-c"

Output

Child process still working...
Child process still working...
sending ctrl c...
Child process is still alive.
Child process: caught ctrl-c
Main process: caught ctrl-c
Batman0730
  • 487
  • 2
  • 5
  • 21