How To Kill A Thread In Python?

Summary: To kill a thread use one of the following methods:

  • Create an Exit_Request flag.
  • Using the multiprocessing Module.
  • Using the trace Module.
  • Using ctypes to raise Exceptions in a thread

Problem: How to kill a thread in Python?

This is one of the most commonly asked questions in Python. Thus, in this article, we are going to address this issue and make sure you have a clear understanding of this topic. Before divining into the topic directly, we will have a look at threading in brief and then move on to our mission-critical question. So without further delay, let the games begin! ? 

Introduction

What is a Thread?

According to Wikipedia, in computer science, a thread of execution is the smallest sequence of programmed instructions that can be managed independently by a scheduler, which is typically a part of the operating system.

➽ Multiple threads can run concurrently within a single program. For example in a word processor, a background thread may be used for spell-checking while a foreground thread may be used to processes user input (keystrokes ), while yet a third thread may be used to load images from the hard drive, and a fourth thread might be busy doing periodic automatic backups of the file being edited.

  • Therefore, threading in Python is used to run multiple threads that can be tasks or function calls, at the same time. Please note that this doesn’t mean that multiple threads are executed on different CPUs.
  • Python threads do not make the program faster in case it already uses 100 % CPU time. That is probably a part of parallel programming which is not within the scope of this discussion.

Note: Threading in Python is itself an entire topic of discussion. The purpose of this introduction is to just get you acquainted with the idea of threads. It is highly recommended that you have some understanding of threading in Python before diving into the topic of killing the thread.

When do we use Threading in Python?

Threads in Python are used in situations where the execution of a task or function call involves some waiting. An example could be interaction with a service hosted on a webserver. Thus, threading allows Python to execute other code while waiting. 

Example:

import threading
import time

print("Printing values from 90 to 100: ")
def loop_thread():
    for t in range(90, 101):
        time.sleep(1)
        print(t)

threading.Thread(target=loop_thread).start()

Output:

Printing values from 90 to 100: 
90
91
92
93
94
95
96
97
98
99
100

Now that have an overview of threads, let us dive into our mission-critical question.

Ways To Kill A Thread In Python

Simply put, killing a thread abruptly is a very bad practice unless absolutely required. Having said that, you might want to kill a thread after a certain duration of time or after some interrupt. So, instead of closing it forcibly, you can kindly ask the thread to go away after ensuring a proper clean up which means:

  • The thread you are trying to kill might be holding a critical resource that must be closed properly.
  • The thread might have created several other threads that must be killed as well before the parent thread can be killed.

Let us understand the numerous ways that help us to do that.

Method 1: Creating An Exit Request Flag

If you are the manager of your own threads, a nice way of handling thread termination is to create an exit flag that each thread checks at regular intervals to know if it is time for it to exit.

Example:

import threading 
import time 
  
def thread_foo(stop):
    while True: 
        print("THREAD STILL RUNNING!") 
        if exit_flag: 
            break

exit_flag = False
t = threading.Thread(target = thread_foo, args =(lambda : exit_flag, )) 
t.start() 
time.sleep(0.1) 
print('Done sleeping! Time to stop the threads.')
exit_flag = True
t.join() 
print('THREAD TERMINATED!')

Output:

In the above example, we created a function that keeps executing the thread until the program encounters the variable exit_flag = True. As soon as that happens, the thread can be killed using the t.join() method.

Note: join() causes the main thread to wait for your thread to finish execution. In other words, join() acts as a “hold” on the main thread. It ensures that your thread has completed its execution before the main thread can move forward. In a way, it assures a clean and proper termination of your thread.

Method 2: Using The Multiprocessing Module

As stated in the Python documentation, multiprocessing is a package that supports spawning processes using an API similar to the threading module. Also, killing a process is much safer than killing a thread because threads share global variables and have a dependency, whereas processes are completely independent and exist separate from each other. The multiprocessing module has the terminate() function which is used to kill a process.

Let us have a look at the following example given below to understand how we can use the multiprocessing module to kill the process.

import multiprocessing
import time
def Child_process():
  while True:
   for i in range (20):  
    print ('Process: ', i)
    time.sleep(0.05)
t = multiprocessing.Process(target = Child_process)
t.start()
time.sleep(0.5)
t.terminate()
print("Child Process successfully terminated")

Output:

Process:  0
Process:  1
Process:  2
Process:  3
Process:  4
Process:  5
Process:  6
Process:  7
Process:  8
Process:  9
Child Process successfully terminated

In the above example after 0.5 seconds the execution of the Child_process was terminated using the terminate() function.

Method 3: Using The trace Module

Another approach to kill a thread is to install trace into the thread that will exit the thread. 

The module given below allows you to kill threads. The class KThread is a drop-in replacement for threading.Thread. It adds the kill() method, which should stop most threads in their tracks.

Disclaimer: The procedure given below has been taken from the following resource: Kill a thread in Python

KThread.py: A killable Thread implementation

import time
import sys
import trace
import threading

class KThread(threading.Thread):
  """A subclass of threading.Thread, with a kill()
method."""
  def __init__(self, *args, **keywords):
    threading.Thread.__init__(self, *args, **keywords)
    self.killed = False

  def start(self):
    """Start the thread."""
    self.__run_backup = self.run
    self.run = self.__run     
    threading.Thread.start(self)

  def __run(self):
    """Hacked run function, which installs the
trace."""
    sys.settrace(self.globaltrace)
    self.__run_backup()
    self.run = self.__run_backup

  def globaltrace(self, frame, why, arg):
    if why == 'call':
      return self.localtrace
    else:
      return None

  def localtrace(self, frame, why, arg):
    if self.killed:
      if why == 'line':
        raise SystemExit()
    return self.localtrace

  def kill(self):
    self.killed = True


# Example Usage
#This illustrates running a function in a separate thread. The thread is killed before the function finishes.
def func():
  print('Function started')
  for i in range(1,100):
    print(i)
    time.sleep(0.2)
  print('Function finished')

A = KThread(target=func)
A.start()
time.sleep(1)
A.kill()

Output:

Function started
1
2
3
4
5

Method 4: Using ctypes To Raise Exceptions In A Thread

In cases when you need to kill a thread forcibly, for example, while wrapping an external library that is busy for long calls and you want to interrupt it, you can use raise_exc() to raise an arbitrary exception, or call terminate() to raise SystemExit automatically. It uses the unexposed PyThreadState_SetAsyncExc function (via ctypes) to raise an exception in the context of the given thread. 

The following code allows (with some restrictions) to raise an Exception in a Python thread:

Example:

import threading
import inspect
import ctypes
import time


def _async_raise(tid, exctype):
    """raises the exception, performs cleanup if needed"""
    if not inspect.isclass(exctype):
        raise TypeError("Only types can be raised (not instances)")
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        # """if it returns a number greater than one, you're in trouble, 
        # and you should call it again with exc=NULL to revert the effect"""
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
        raise SystemError("PyThreadState_SetAsyncExc failed")


class Thread(threading.Thread):
    def _get_my_tid(self):
        """determines this (self's) thread id"""
        if not self.is_alive():
            raise threading.ThreadError("the thread is not active")
        
        # do we have it cached?
        if hasattr(self, "_thread_id"):
            return self._thread_id
        
        # no, look for it in the _active dict
        for tid, tobj in threading._active.items():
            if tobj is self:
                self._thread_id = tid
                return tid
        
        raise AssertionError("could not determine the thread's id")
    
    def raise_exc(self, exctype):
        """raises the given exception type in the context of this thread"""
        _async_raise(self._get_my_tid(), exctype)
    
    def terminate(self):
        """raises SystemExit in the context of the given thread, which should 
        cause the thread to exit silently (unless caught)"""
        self.raise_exc(SystemExit)

def f():
     try:
         while True:
            for i in range(10000):
             print(i) 
             time.sleep(0.1)
     finally:
         print ("TERMINATING!!!")

t = Thread(target = f)
t.start()
time.sleep(0.6)
t.terminate()
t.join()

Output:

0
1
2
3
4
5
TERMINATING!!!

Conclusion

The key takeaways from this article were:

  • What is Thread?
  • Ways to kill a thread in Python:
    • Creating an Exit_Request flag.
    • Using the Multiprocessing Module.
    • Using the trace Module.
    • Using ctypes to raise Exceptions in a thread

Please subscribe and stay tuned for more interesting articles!

References

  1. https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread
  2. http://net-informations.com/python/iq/kill.htm
  3. https://pybay.com/site_media/slides/raymond2017-keynote/threading.html
  4. http://tomerfiliba.com/recipes/Thread2/

Nerd Humor

Oh yeah, I didn’t even know they renamed it the Willis Tower in 2009, because I know a normal amount about skyscrapers.xkcd (source)

Where to Go From Here?

Enough theory. Let’s get some practice!

Coders get paid six figures and more because they can solve problems more effectively using machine intelligence and automation.

To become more successful in coding, solve more real problems for real people. That’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?

You build high-value coding skills by working on practical coding projects!

Do you want to stop learning with toy projects and focus on practical code projects that earn you money and solve real problems for people?

🚀 If your answer is YES!, consider becoming a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.

If you just want to learn about the freelancing opportunity, feel free to watch my free webinar “How to Build Your High-Income Skill Python” and learn how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!