python sys.exit vs. os._exit

By Brian Fitzgerald

Here are some notes on the behavior of python functions sys.exit() vs os._exit() in a threaded program.

from threading import Thread, currentThread
from time import sleep, time
import sys
import atexit

def pt(str=None):
    print('el=%ss th=%s: %s' % (
        round(time() - t0, 1),
        currentThread().name, str)
          )

def testexit():
    pt('sleeping')
    sleep(int(currentThread().getName()))
    pt('calling sys.exit')
    sys.exit(0)
    pt('returning')

def alldone():
    pt('all done')

t0 = time()
atexit.register(alldone)
threads = []
for i in [1, 2]:
    th = Thread(target=testexit)
    th.setName(i)
    th.setDaemon(False)
    th.start()
    threads.append(th)
for th in threads:
    pt('waiting to join thread th=%s' % th.name)
    th.join()
    pt('main: joined to th=%s' % th.name)

In the threads, the sleep time equals the thread id, i.e. 1 or 2 seconds. We have arranged that function alldone will execute when the program exits.

"C:\Users\Brian Fitzgerald\PycharmProjects\blog\venv\Scripts\python.exe" "C:/Users/Brian Fitzgerald/PycharmProjects/blog/threadexit.py"
el=0.0s th=1: sleeping
el=0.0s th=2: sleeping
el=0.0s th=MainThread: waiting to join thread th=1
el=1.0s th=1: calling sys.exit
el=1.0s th=MainThread: main: joined to th=1
el=1.0s th=MainThread: waiting to join thread th=2
el=2.0s th=2: calling sys.exit
el=2.0s th=MainThread: main: joined to th=2
el=2.0s th=MainThread: all done
Process finished with exit code 0

Notes:

  • sys.exit() causes the thread to exit
  • statement “pt(‘returning’)” is not reached
  • The main thread finishes
  • Function alldone is executed
  • The output is identical if th.setDaemon(True)

Now changing “import sys” to “import os”, and “sys.exit(0)” to “os._exit(0)”:

from threading import Thread, currentThread
from time import sleep, time
import os
import atexit

def pt(str=None):
    print('el=%ss th=%s: %s' % (
        round(time() - t0, 1),
        currentThread().name, str)
          )

def testexit():
    pt('sleeping')
    sleep(int(currentThread().getName()))
    pt('calling os._exit')
    os._exit(0)
    pt('returning')

def alldone():
    pt('all done')

t0 = time()
atexit.register(alldone)
threads = []
for i in [1, 2]:
    th = Thread(target=testexit)
    th.setName(i)
    th.setDaemon(False)
    th.start()
    threads.append(th)

for th in threads:
    pt('waiting to join thread th=%s' % th.name)
    th.join()
    pt('main: joined to th=%s' % th.name)
"C:\Users\Brian Fitzgerald\PycharmProjects\blog\venv\Scripts\python.exe" "C:/Users/Brian Fitzgerald/PycharmProjects/blog/threadexit.py"
el=0.0s th=1: sleeping
el=0.0s th=2: sleeping
el=0.0s th=MainThread: waiting to join thread th=1
el=1.0s th=1: calling os._exit

Process finished with exit code 0

Notes:

  • MainThread is terminated while waiting to join thread 1.
  • thread 2 is terminated while sleeping
  • alldone is not reached
  • The output is identical if th.setDaemon(True)

Beware that os._exit can terminate a thread while it is in an exception handler:

def testexit():
    pt('try')
    try:
        raise Exception()
    except:
        pt('sleeping')
        sleep(int(currentThread().getName()))
        pt('done except')
    finally:
        pt('done finally')
    pt('calling os._exit')
    os._exit(0)
    pt('returning')
"C:\Users\Brian Fitzgerald\PycharmProjects\blog\venv\Scripts\python.exe" "C:/Users/Brian Fitzgerald/PycharmProjects/blog/threadexit.py"
el=0.0s th=1: try
el=0.0s th=1: sleeping
el=0.0s th=MainThread: waiting to join thread th=1
el=0.0s th=2: try
el=0.0s th=2: sleeping
el=1.0s th=1: done except
el=1.0s th=1: done finally
el=1.0s th=1: calling os._exit

Process finished with exit code 0

Note:

  • In thread 2, pt(‘done except’) is not reached.

os._exit can also interrupt a finally block:

def testexit():
    pt('try')
    try:
        raise Exception()
    except:
        pt('done except')
    finally:
        pt('sleeping')
        sleep(int(currentThread().getName()))
        pt('done finally')
    pt('calling os._exit')
    os._exit(0)
    pt('returning')
"C:\Users\Brian Fitzgerald\PycharmProjects\blog\venv\Scripts\python.exe" "C:/Users/Brian Fitzgerald/PycharmProjects/blog/threadexit.py"
el=0.0s th=1: try
el=0.0s th=1: done except
el=0.0s th=1: sleeping
el=0.0s th=2: try
el=0.0s th=2: done except
el=0.0s th=MainThread: waiting to join thread th=1
el=0.0s th=2: sleeping
el=1.0s th=1: done finally
el=1.0s th=1: calling os._exit

Process finished with exit code 0

Note:

  • In thread 2, pt(‘done finally’) is not reached

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s