Question

This could be a stupid question, but I'm testing out some of my assumptions about Python and I'm confused as to why the following code snippet would not exit when called in the thread, but would exit when called in the main thread.

import sys, time
from threading import Thread

def testexit():
    time.sleep(5)
    sys.exit()
    print "post thread exit"

t = Thread(target = testexit)
t.start()
t.join()
print "pre main exit, post thread exit"
sys.exit()
print "post main exit"

The docs for sys.exit() state that the call should exit from Python. I can see from the output of this program that "post thread exit" is never printed, but the main thread just keeps on going even after the thread calls exit.

Is a separate instance of the interpreter being created for each thread, and the call to exit() is just exiting that separate instance? If so, how does the threading implementation manage access to shared resources? What if I did want to exit the program from the thread (not that I actually want to, but just so I understand)?

Was it helpful?

Solution

sys.exit() raises the SystemExit exception, as does thread.exit(). So, when sys.exit() raises that exception inside that thread, it has the same effect as calling thread.exit(), which is why only the thread exits.

OTHER TIPS

What if I did want to exit the program from the thread?

Apart from the method Deestan described you can call os._exit (notice the underscore). Before using it make sure that you understand that it does no cleanups (like calling __del__ or similar).

What if I did want to exit the program from the thread (not that I actually want to, but just so I understand)?

At least on Linux you could do something like:

os.kill(os.getpid(), signal.SIGINT)

This send a SIGINT to the main thread where it can be handled as a KeyboardInterrupt.

BTW: On Windows you can only send a SIGTERM signal, which cannot be caught from Python. (there I would prefer calling os._exit as suggested by Helmut)

Is the fact that "pre main exit, post thread exit" is printed what's bothering you?

Unlike some other languages (like Java) where the analog to sys.exit (System.exit, in Java's case) causes the VM/process/interpreter to immediately stop, Python's sys.exit just throws an exception: a SystemExit exception in particular.

Here are the docs for sys.exit (just print sys.exit.__doc__):

Exit the interpreter by raising SystemExit(status).
If the status is omitted or None, it defaults to zero (i.e., success).
If the status is numeric, it will be used as the system exit status.
If it is another kind of object, it will be printed and the system
exit status will be one (i.e., failure).

This has a few consequences:

  • in a thread it just kills the current thread, not the entire process (assuming it gets all the way to the top of the stack...)
  • object destructors (__del__) are potentially invoked as the stack frames that reference those objects are unwound
  • finally blocks are executed as the stack unwinds
  • you can catch a SystemExit exception

The last is possibly the most surprising, and is yet another reason why you should almost never have an unqualified except statement in your Python code.

What if I did want to exit the program from the thread (not that I actually want to, but just so I understand)?

My preferred method is Erlang-ish message passing. Slightly simlified, I do it like this:

import sys, time
import threading
import Queue # thread-safe

class CleanExit:
  pass

ipq = Queue.Queue()

def testexit(ipq):
  time.sleep(5)
  ipq.put(CleanExit)
  return

threading.Thread(target=testexit, args=(ipq,)).start()
while True:
  print "Working..."
  time.sleep(1)
  try:
    if ipq.get_nowait() == CleanExit:
      sys.exit()
  except Queue.Empty:
    pass
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top