0

I'm experiencing some unexpected behavior with os.execl on Windows with Python 3.3.2 (this may well apply in other places, but this is the only environment I've attempted this in). My goal in this example is to be able to restart a currently running program on KeyboardInterrupt. My code:

import os
import sys
import time

def main():
    print("Welcome.")
    while True:
        try:
            print("Hello.")
            time.sleep(10)
        except KeyboardInterrupt:
            break
    args = sys.argv
    args[0] = '"' + args[0] + '"'
    # This should restart the program.
    os.execl(sys.executable, sys.executable, * args)

if __name__ == '__main__':
    main()

When I run my program by simply double clicking on the .py file, and then keyboard interrupt, everything goes exactly as expected. My program restarts, and I see a second Welcome message. I can do this any number of times without issue.

When I run via command line (either by typing python myprog.py or simply myprog.py), some funky things seem to happen. Upon issuing a KeyboardInterrupt, the program seems to stop without restarting. When I look in my task manager, I curiously still see a python.exe running. If I run my program again from the command line, I immedieately see:

Welcome
Hello
Welcome
Hello

If I KeyboardInterrupt out of this again, I now see two rogue python.exe processes sitting in my task manager. Sure enough if I run a third time from the command line, I now see three Welcome/Hello messages.

Would love to know if this is the expected behavior, or if there's something else I need to be doing to make running from the command line work in this situation?

repole
  • 305
  • 1
  • 14
  • On Windows, `exec` creates a new process and exits the current process. So the parent (probably cmd.exe) resumes as the foreground console process. If you restart with `subprocess.Popen` instead, then you can pass `creationflags=subprocess.CREATE_NEW_CONSOLE`. That way the new Python instance won't compete with cmd.exe (or whatever the parent process was) for the console foreground. – Eryk Sun Apr 28 '15 at 23:37
  • Have a look at http://stackoverflow.com/questions/7004687/os-exec-on-windows, which looks like the same issue, though I'm not sure it fully answers this. – Andrew Janke Apr 28 '15 at 23:38
  • @eryksun - Popen with CREATE_NEW_CONSOLE gets the job done, greatly appreciate the help. – repole Apr 28 '15 at 23:48
  • @AndrewJanke - I noticed the caveats about windows and os.exec in the documentation, but the part that seems especially strange is that it works fine when run directly through the python launcher, while the command line specifically fails. I'm assuming the launcher must be doing something special to handle that situation. – repole Apr 28 '15 at 23:51
  • 2
    @repole, if the parent process is a GUI process such as explorer.exe, as opposed to a console process such as cmd.exe, then it isn't waiting for the child to exit and then resuming as the console foreground process. – Eryk Sun Apr 28 '15 at 23:56
  • @eryksun - That makes sense, hadn't considered that the console was essentially fighting for control back. – repole Apr 29 '15 at 00:06
  • Yep. If you take a look at your processes in Sysinternals Process Explorer's tree view, you can see what's going on: when double-clicking the file to run it, you get a `py.exe` and `python.exe`, with no `cmd.exe` involved. You can get the same effect using `start` when launching from the command line: `start C:\windows\py.exe C:\path\to\your\script.py`. – Andrew Janke Apr 29 '15 at 00:10
  • @repole, you mean cmd.exe is competing for the foreground, not the console. The console window is hosted by another process (conhost.exe). Multiple processes can be attached to a single console host, including cmd.exe, powershell.exe, python.exe, etc, but it's an awful mess if more than one wants to be the foreground process simultaneously. – Eryk Sun Apr 29 '15 at 00:11
  • @AndrewJanke, you'll get the same problem as in this question if you use `start /b C:\path\to\your\script.py` to have it run in the current console window, but without the `/w` option that would force cmd.exe to wait in the background. (BTW, there's no need to run py.exe explicitly; the .py extension should be associated with it.) – Eryk Sun Apr 29 '15 at 00:16
  • it's not like forked python process and cmd.exe fight, when you run script first time, cmd.exe wait it to exit, what happen when you fork process. but new python process getting same file handles for console I/O and is not tracked anymore by cmd.exe so the both start shitting there. The solution is to have a "third party middle-man" like py.exe or whatever, which stay alive and cmd.exe keep track of it, while main python process could be forked – Reishin Jan 23 '21 at 23:41

0 Answers0