How to exit the entire application from a Python thread?
Asked Answered
P

6

106

How can I exit my entire Python application from one of its threads? sys.exit() only terminates the thread in which it is called, so that is no help.

I would not like to use an os.kill() solution, as this isn't very clean.

Pauperism answered 28/9, 2009 at 22:20 Comment(1)
I know you don't want one, but for those who do want an os.kill() solution, you could do os.kill(os.getpid(), signal.SIGTERM); be sure to import os and signal first, of course. This is nice because it lets you break out of input statements in the main thread from another thread to quit the program.Doncaster
I
70

If all your threads except the main ones are daemons, the best approach is generally thread.interrupt_main() -- any thread can use it to raise a KeyboardInterrupt in the main thread, which can normally lead to reasonably clean exit from the main thread (including finalizers in the main thread getting called, etc).

Of course, if this results in some non-daemon thread keeping the whole process alive, you need to followup with os._exit as Mark recommends -- but I'd see that as the last resort (kind of like a kill -9;-) because it terminates things quite brusquely (finalizers not run, including try/finally blocks, with blocks, atexit functions, etc).

Impressment answered 29/9, 2009 at 0:17 Comment(2)
It seems that is in fact not the best approach, as it was not added to threading in Python 3.Turgid
In Python3, this function becomes _thread.interrupt_mainCrispen
P
115

Short answer: use os._exit.

Long answer with example:

I yanked and slightly modified a simple threading example from a tutorial on DevShed:

import threading, sys, os

theVar = 1

class MyThread ( threading.Thread ):

   def run ( self ):

      global theVar
      print 'This is thread ' + str ( theVar ) + ' speaking.'
      print 'Hello and good bye.'
      theVar = theVar + 1
      if theVar == 4:
          #sys.exit(1)
          os._exit(1)
      print '(done)'

for x in xrange ( 7 ):
   MyThread().start()

If you keep sys.exit(1) commented out, the script will die after the third thread prints out. If you use sys.exit(1) and comment out os._exit(1), the third thread does not print (done), and the program runs through all seven threads.

os._exit "should normally only be used in the child process after a fork()" -- and a separate thread is close enough to that for your purpose. Also note that there are several enumerated values listed right after os._exit in that manual page, and you should prefer those as arguments to os._exit instead of simple numbers like I used in the example above.

Phoebephoebus answered 28/9, 2009 at 23:21 Comment(1)
This works especially well when running in a docker container. The issue in a docker container is that we can't kill pid 1. Using os._exit(1) worked.Debris
I
70

If all your threads except the main ones are daemons, the best approach is generally thread.interrupt_main() -- any thread can use it to raise a KeyboardInterrupt in the main thread, which can normally lead to reasonably clean exit from the main thread (including finalizers in the main thread getting called, etc).

Of course, if this results in some non-daemon thread keeping the whole process alive, you need to followup with os._exit as Mark recommends -- but I'd see that as the last resort (kind of like a kill -9;-) because it terminates things quite brusquely (finalizers not run, including try/finally blocks, with blocks, atexit functions, etc).

Impressment answered 29/9, 2009 at 0:17 Comment(2)
It seems that is in fact not the best approach, as it was not added to threading in Python 3.Turgid
In Python3, this function becomes _thread.interrupt_mainCrispen
P
28

Using thread.interrupt_main() may not help in some situation. KeyboardInterrupts are often used in command line applications to exit the current command or to clean the input line.

In addition, os._exit will kill the process immediately without running any finally blocks in your code, which may be dangerous (files and connections will not be closed for example).

The solution I've found is to register a signal handler in the main thread that raises a custom exception. Use the background thread to fire the signal.

import signal
import os
import threading
import time


class ExitCommand(Exception):
    pass


def signal_handler(signal, frame):
    raise ExitCommand()


def thread_job():
    time.sleep(5)
    os.kill(os.getpid(), signal.SIGUSR1)


signal.signal(signal.SIGUSR1, signal_handler)
threading.Thread(target=thread_job).start()  # thread will fire in 5 seconds
try:
    while True:
        user_input = raw_input('Blocked by raw_input loop ')
        # do something with 'user_input'
except ExitCommand:
    pass
finally:
    print('finally will still run')

Related questions:

Padova answered 21/8, 2014 at 6:37 Comment(3)
This won't work on windows AttributeError: module 'signal' has no attribute 'SIGUSR1'Erk
Is there an alternative to this for Windows?Partida
If a process is terminated, its files and connections are closed. It's a fundamental feature of operating systems.Vender
L
6

The easiest way to exit the whole program is, we should terminate the program by using the process id (pid).

import os
import psutil

current_system_pid = os.getpid()

ThisSystem = psutil.Process(current_system_pid)
ThisSystem.terminate()

To install psutl:- "pip install psutil"

Lavadalavage answered 20/8, 2020 at 20:30 Comment(3)
This answer is what I wanted for several days' struggling.Idiopathy
In my opinion, this is the simplest and best answer to this question. Thanks!Mythomania
Actually, there's an even simpler way without bringing in any dependencies: os.kill(os.getpid(), signal.SIGTERM)Saintebeuve
G
4

For Linux you can use the kill() command and pass the current process' ID and the SIGINT signal to start the steps to exit the app.

import signal

os.kill(os.getpid(), signal.SIGINT)
Gilda answered 16/5, 2022 at 7:39 Comment(1)
just to mention, you need to import signalDefinitely
C
0

Use threading.Event()

It allows you to handle errors and works on Windows and Linux.

Use this script to end all threads whenever you reach your desired threshold. In this case, I use it as a timeout.

Other solutions rely on potentially problematic os._exit, which this intentionally does not so that you can handle exceptions with try/except/finally blocks instead of just exiting. It also works for Python 2 and 3, which many answers do not.

This script will wait until either of your functions completes before finishing.

import time, queue, threading

def my_func(s):  # Function that you want to set a time limit for.
    # Insert your code here. Sleep is used to mimic operation time.
    print('Running my_func for {}s'.format(s))
    time.sleep(s)
    print('my_func complete {}s'.format(time.time()-t0))
    e.set()

def timeout_func(s):  # Controls timeout
    print('Starting timeout_func for {}s'.format(s))
    time.sleep(s)
    print('timeout_func complete {}s'.format(time.time()-t0))
    e.set()

t0 = time.time()
q = queue.Queue()
myfunc_runtime = 5  # Mimics the amount of time your function runs
timeout_threshold = 10  # Seconds until timeout

# Initialize and start threads
thread_timeout = threading.Thread(target=timeout_func, args=[timeout_threshold])
thread_myfunc = threading.Thread(target=my_func, args=[myfunc_runtime])
thread_timeout.daemon = True  # Essential for event to stop thread
thread_myfunc.daemon = True  # Essential for event to stop thread
e = threading.Event()
thread_timeout.start()
thread_myfunc.start()

# Wait until your event is set. Script completion time is always the minimum of runtime for both funcs
e.wait()
print('Script completion time: ' + str(time.time()-t0))

Cocoon answered 12/1 at 0:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.