How to Kill a Thread in Python

April 7, 2022 Python Threading

You can kill a thread by killing its parent process via the terminate() and kill() methods.

In this tutorial you will discover how to kill a thread in Python.

Let's get started.

Need to Kill a Thread

A thread is a thread of execution in a computer program.

Every Python program has at least one thread of execution called the main thread. Both processes and threads are created and managed by the underlying operating system.

Sometimes we may need to create additional threads in our program in order to execute code concurrently.

Python provides the ability to create and manage new threads via the threading module and the threading.Thread class.

You can learn more about Python threads in the guide:

In concurrent programming, you sometimes need to forcefully terminate or kill a thread.

Killing a thread means that there is no facility to gracefully stop the thread.

This may be for many reasons, such as:

How can we kill a thread in Python?

Alternatives to Killing a Thread

Forcefully terminating or killing a thread is a drastic action.

Before we look at how to kill a thread, let's look at alternatives.

There are perhaps three common alternatives you may want to consider they are:

  1. Stop the thread.
  2. Raise an exception in the thread.
  3. Make the thread a daemon thread.

Let's take a closer look at each in turn.

Stop a Thread

Python does not provide the ability in the threading API to stop a thread.

Instead, we can add this functionality to our code directly.

A thread can be stopped using a shared boolean variable such as a threading.Event.

A threading.Event is a thread-safe boolean variable flag that can be either set or not set. It can be shared between threads and checked and set without fear of a race condition.

A new event can be created and then shared between threads, for example:

...
# create a shared event
event = Event()

The event is created in the 'not set' or False state.

We may have a task in a custom function that is run in a new thread. The task may iterate, such as in a while-loop or a for-loop.

For example:

# custom task function
def task():
    # perform task in iterations
    while True:
        # ...

We can update our task function to check the status of an event each iteration.

If the event is set true, we can exit the task loop or return from the task() function, allowing the new thread to terminate.

The status of the threading.Event can be checked via the is_set() function.

For example:

# custom task function
def task():
    # perform task in iterations
    while True:
        # ...
        # check for stop
        if event.is_set():
            break

The main thread, or another thread, can then set the event in order to stop the new thread from running.

The event can be set or made True via the set() function.

For example:

...
# stop the thread
event.set()
# wait for the new thread to stop
thread.join()

You can learn more about stopping a thread in this tutorial:

Raise Exception in Thread

Like stopping a thread, the Python threading API does not provide a mechanism to raise an exception in a target thread.

Instead, we can add this functionality to our code directly using a threading.Event.

As with stopping a thread, we can create an event and use it as a thread-safe shared boolean variable. A new event can be created and then shared between threads, for example:

...
# create a shared event
event = Event()

Our target task function executing in a new thread can check the status of the event each iteration of the task.

If set, the task function can raise an exception. The exception will not be handled and instead we will let it bubble up to the top level of the thread, in which case the thread will terminate.

For example:

# custom task function
def task():
    # perform task in iterations
    while True:
        # ...
        # check for an exception
        if event.is_set():
            raise Exception('Received request to halt')

The main thread, or another thread, can then set the event in order to trigger an exception to stop the new thread.

The event can be set or made True via the set() function.

For example:

...
# raise
event.set()
# wait for the new thread to stop
thread.join()

You can learn more about unexpected exceptions in threads in this tutorial:

Make Daemon Thread

A thread may be configured to be a daemon thread.

Daemon threads is the name given to background threads. By default, threads are non-daemon threads.

A Python program will only exit when all non-daemon threads have finished. For example, the main thread is a non-daemon thread. This means that daemon threads can run in the background and do not have to finish or be explicitly excited for the program to end.

We can determine if a thread is a daemon thread via the "daemon" attribute.

...
# report the daemon attribute
print(thread.daemon)

A thread can be configured to be a daemon by setting the "daemon" argument to True in the threading.Thread constructor.

For example:

...
# create a daemon thread
thread = Thread(daemon=True)

We can also configure a thread to be a daemon thread after it has been constructed via the "daemon" property.

For example:

...
# configure the thread to be a daemon
thread.daemon = True

You can learn more about daemon threads in this tutorial:

Now that we know some alternatives, let's look at how to kill a thread.

How to Kill a Thread

A thread can be terminated or killed by forcibly terminating or killing its parent process.

Recall that each thread belongs to a process. A process is an instance of the Python interpreter, and a thread is a thread of execution that executes code within a process. Each process starts with one default thread called the main thread.

Killing a thread via its parent process may mean that you will want to first create a new process in which to house any new threads that you may wish to forcefully terminate. This is to avoid terminating the main process.

There are two main approaches to killing a thread's parent process, they are:

  1. Using code within the program.
  2. Using commands external to the program.

Let's take a look at each in turn.

Killing a Process With Code

A process can be killed by calling the terminate() or kill() methods on the multiprocessing.Process instance.

Each process in python has a corresponding instance of the multiprocessing.Process class.

We can get the current process instance by calling the multiprocessing.current_process() function.

For example:

...
# get the current process
process = multiprocessing.current_process()

Alternatively, we may hang onto the multiprocessing.Process instance if we create a new process in which to execute the thread we may wish to kill.

...
# create a new process
process = multiprocessing.Process(...)

We can then call the terminate() method on the process instance to kill it.

This will send the process the SIGTERM signal which means "Signal Terminate".

For example:

...
# kill the process
process.terminate()

Once the signal is received, the process will terminate, in turn terminating its child threads. It will not terminate any child process.

This signal can be caught and handled within the process, if we so desire. As such, it may be helpful we have clean-up tasks to perform prior to killing.

Alternatively, we may call the kill() function on the process instance to kill it.

This will send the SIGKILL signal to the process, which means "Signal Kill".

Once this signal is received, the process will terminate like "SIGTERM", killing all child threads and not killing any child processes.

For example:

...
# kill the process
process.kill()

Unlike SIGTERM, the SIGKILL cannot be handled within the process. It is a more forceful way of terminating the process.

Killing a Process Externally

A Python thread can be killed by killing its parent process external to the program.

This can be achieved by sending a signal to the parent process.

If the Python program is running in a terminal (command prompt) and can be made active, then you can send a signal directly to the process using the keyboard.

For example:

Alternatively, if the process cannot be made active, e.g. is running in the background, then a command can be used to send a signal to the process directly.

Note, this applies to a POSIX operating system such as Linux or MacOS.

The process id for the Python process can be identified, such as using the "top" command or the "ps" command.

Then the kill command can be used to stop the process by sending specific signals.

For example:

kill -9 <process_id>

This will send the SIGKILL or "signal kill" to the process, which will forcefully terminate the process and its child threads.

Next, let's look at some worked examples of killing a thread via its parent process.

Example of Terminating a Thread

We can explore how to kill a thread via its parent process by calling the terminate() method.

In this example, we will first create a new child process. The child process will then execute our task in the main thread of the process. The task will loop forever, each iteration it will block for one second then report a message. It provides no way to gracefully terminate. Once the thread is started, we will wait for some time, then forcefully kill the thread via its parent process, wait a moment longer and then terminate the initial process.

First, we can define a task that will loop forever and report a message each second.

The task() function listed below implements this.

# task to run in a new thread
def task():
    # run for ever
    while True:
        # block for a moment
        sleep(1)
        # report a message
        print('Task is running', flush=True)

Next, because we are using new processes, we need to protect the entry point.

...
# entry point
if __name__ == '__main__':
	# ...

We can then create a new instance of the multiprocessing.Process class, configured to execute our task() function in the main thread of the process. The start() method can then be called to run the new process and new main thread.

...
# create a new process with a new thread
process = Process(target=task)
# start the new process and new thread
process.start()

Back in the main thread of our first process, we will block for a while to let the new task run.

...
# wait a while
sleep(5)

We can then forcefully kill the new main thread by calling the terminate() function on the thread's parent process.

This will stop the thread immediately.

...
print('Killing the thread via its process')
process.terminate()

Next, back in the main thread of our first process, we will block for a little longer, to show that this thread is still running and in our control before terminating.

...
# wait a while
sleep(2)
# all done
print('All done, stopping')

Tying this together, the complete example of killing a thread by terminating its parent process is listed below.

# SuperFastPython.com
# example of killing a thread via its process
from time import sleep
from multiprocessing import Process
from threading import Thread

# task to run in a new thread
def task():
    # run for ever
    while True:
        # block for a moment
        sleep(1)
        # report a message
        print('Task is running', flush=True)

# entry point
if __name__ == '__main__':
    # create a new process with a new thread
    process = Process(target=task)
    # start the new process and new thread
    process.start()
    # wait a while
    sleep(5)
    # kill the new thread via the new process
    print('Killing the thread via its process')
    process.terminate()
    # wait a while
    sleep(2)
    # all done
    print('All done, stopping')

Running the example first created a new process and then started a new main thread to execute our task() function.

Our task function would run forever unless the parent process is forcefully killed.

The first process blocks for a moment to allow the new task to run for a while. It then wakes up and kills the task by terminating the parent thread.

This sends the SIGTERM signal terminated to the new process, which is not handled by the process and terminates the process and its child main thread immediately.

The main thread of the first process then runs a little longer, blocks for a moment, reports a final message and it also terminates.

This shows that we can kill a new thread by killing its parent process and it has no effect on other threads running in separate processes.

Task is running
Task is running
Task is running
Task is running
Killing the thread via its process
All done, stopping

Next, let's look at killing a thread by killing its parent process.

Example of Killing a Thread

We can explore how to kill a thread via its parent process by calling the kill() method.

The example from the previous section can be updated to kill the new task thread by killing the threads parent process.

This can be achieved by calling the kill() method on the parent process directly from the first process in which we created and started the new thread and new process.

...
# kill the new thread via the new process
print('Killing the thread via its process')
process.kill()

Tying this together, the complete example of killing a thread by killing its parent process is listed below.

# SuperFastPython.com
# example of killing a thread via its process
from time import sleep
from multiprocessing import Process
from threading import Thread

# task to run in a new thread
def task():
    # run for ever
    while True:
        # block for a moment
        sleep(1)
        # report a message
        print('Task is running', flush=True)

# entry point
if __name__ == '__main__':
    # create a new process with a new thread
    process = Process(target=task)
    # start the new process and new thread
    process.start()
    # wait a while
    sleep(5)
    # kill the new thread via the new process
    print('Killing the thread via its process')
    process.kill()
    # wait a while
    sleep(2)
    # all done
    print('All done, stopping')

Running the example first created a new process and then started a new main thread to execute our task() function.

Our task function would run forever unless the parent process is forcefully killed.

The first process blocks for a moment to allow the new task to run for a while. It then wakes up and kills the task by killing the parent thread.

This sends the SIGKILL signal terminated to the new process, which cannot be handled by the process and kills the process and its child main thread immediately.

The main thread of the first process then runs a little longer, blocks for a moment, reports a final message and it also terminates.

This shows that we can kill a new thread by killing its parent process and it has no effect on other threads running in separate processes.

Task is running
Task is running
Task is running
Task is running
Killing the thread via its process
All done, stopping

Takeaways

You now know how to kill a thread.



If you enjoyed this tutorial, you will love my book: Python Threading Jump-Start. It covers everything you need to master the topic with hands-on examples and clear explanations.