Hướng dẫn python thread not stopping

Last Updated on September 12, 2022

You can stop a thread by using a threading.Event.

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

Let’s get started.

Table of Contents

  • Need to Stop a Thread
  • How to Stop a Thread
  • Example of Stopping a Thread With a Custom Function
    • Custom Function in a New Thread
    • Stop Custom Function in New Thread
  • Example of Stopping a Thread With an Extended Class
    • Custom Thread Class
    • Stop Custom Thread Class
  • Common Questions About Stopping Threads
    • What if My Task Does Not Have a Loop?
    • What if My Task Raises An Exception?
    • What if My New Thread Has Already Stopped?
    • What if My New Thread is a Daemon Thread?
    • How Can We Stop Multiple Threads?
    • How Can We Stop Daemon Threads?
    • How Can We Stop Tasks in a ThreadPoolExecutor?
  • Further Reading
  • Takeaways

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:

  • Threading in Python: The Complete Guide

In concurrent programming, we may run a task in a new thread, then later decide to stop the task.

This may be for many reasons, such as:

  • The result from the task is no longer required.
  • The application is shutting down.
  • The outcome from the task has gone astray.

Python provides no way to stop a running thread in the API.

How can we stop a thread in Python?

Got slow loops? Run your loops in parallel (using all CPUs)
Learn how by downloading my FREE ebook: Parallel Loops in Python

How to Stop a Thread

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.

If you are new to threading.Events, you can learn more here:

  • How to Use an Event Object In Python

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

whileTrue:

# ...

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

whileTrue:

# ...

        # 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:

...

# set the event

event.set()

# wait for the new thread to stop

thread.join()

Now that we know how to stop a Python thread, let’s look at some worked examples.

Confused by the threading module API?
Download my FREE PDF cheat sheet

Example of Stopping a Thread With a Custom Function

In this section we can explore how to stop a thread that is executing a custom function.

First, we will develop an example that runs a custom function in a separate thread, then we will look at how to update the example to stop the thread on demand.

Custom Function in a New Thread

We can develop an example that runs a function in a new thread.

The new task function will execute in a loop and once finished the new thread will terminate and the main thread will terminate.

Firstly, we can define the task function.

The function will execute a loop five times. Each iteration it will block for a second, then report a message in an effort to simulate work and show progress.

Once the task is finished, the function will report a final message.

The task() function below implements this.

# custom task function

def task():

    # execute a task in a loop

    foriinrange(5):

        # block for a moment

        sleep(1)

        # report a message

        print('Worker thread running...')

    print('Worker closing down')

Next, in the main thread we can create a new threading.Thread instance that is configured to execute our task() function in a new thread via the “target” argument.

...

# create and configure a new thread

thread=Thread(target=task)

We can then immediately start the new thread via the start() function.

...

# start the new thread

thread.start()

The main thread will then wait for the new thread to finish by joining the thread.

If you are new to joining threads, you can learn more here:

  • How to Join a Thread in Python

Tying this together, the complete example is listed below.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

# SuperFastPython.com

# example of a thread executing a custom function

from time import sleep

from threading import Thread

# custom task function

def task():

    # execute a task in a loop

    foriinrange(5):

        # block for a moment

        sleep(1)

        # report a message

        print('Worker thread running...')

    print('Worker closing down')

# create and configure a new thread

thread= Thread(target=task)

# start the new thread

thread.start()

# wait for the new thread to finish

thread.join()

Running the example first creates and starts the new thread.

The main thread then blocks until the new thread finishes.

The new thread executes in a loop, blocking for a moment and reporting progress. After five iterations of the loop, the new thread reports a final message and terminates.

The main thread notices that the new thread has finished and then terminates itself, closing the program.

Worker thread running...

Worker thread running...

Worker thread running...

Worker thread running...

Worker thread running...

Worker closing down

Next, let’s look at how we might update this example to stop the thread on demand.

Stop Custom Function in New Thread

We can update the example from the previous section to stop the new thread on demand.

This can be achieved by creating a new threading.Event instance, passing it as an argument to the new thread, and then updating the custom function to check if the event is set each iteration. Once the event is set, the function can break its task loop and exit, terminating the new thread.

Firstly, we can update the task function to take the shared threading.Event instance as an argument.

# custom task function

def task(event):

# ...

We can then update the task loop to check the status of the event each iteration, and if set to break the task loop.

...

# check for stop

ifevent.is_set():

    break

Tying this together, the updated task() function with these changes is listed below.

# custom task function

def task(event):

    # execute a task in a loop

    foriinrange(5):

        # block for a moment

        sleep(1)

        # check for stop

        ifevent.is_set():

            break

        # report a message

        print('Worker thread running...')

    print('Worker closing down')

Next, in the main thread can first create a new threading.Event instance to be shared between the threads.

...

# create the event

event=Event()

We can then update the main thread to block for a few seconds.

...

# block for a while

sleep(3)

Finally, we can set the event and trigger the new thread to stop.

...

# stop the worker thread

print('Main stopping thread')

event.set()

Tying this together, the complete example is listed below.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

# SuperFastPython.com

# example of stopping a new thread

from time import sleep

from threading import Thread

from threading import Event

# custom task function

def task(event):

    # execute a task in a loop

    foriinrange(5):

        # block for a moment

        sleep(1)

        # check for stop

        ifevent.is_set():

            break

        # report a message

        print('Worker thread running...')

    print('Worker closing down')

# create the event

event=Event()

# create and configure a new thread

thread =Thread(target=task,args=(event,))

# start the new thread

thread.start()

# block for a while

sleep(3)

# stop the worker thread

print('Main stopping thread')

event.set()

# wait for the new thread to finish

thread.join()

Running the example first creates and starts the new thread.

The main thread then blocks for a few seconds.

Meanwhile, the new thread executes its task loop, blocking and reporting a message each iteration. It checks the event each iteration, which remains false and does not trigger the thread to stop.

The main thread wakes up, and then sets the event. It then joins the new thread, waiting for it to terminate.

The task thread checks the event which is discovered to be set (e.g, True). The thread breaks the task loop, reports a final message then terminates the new thread.

The main thread then terminates, closing the Python process.

Worker thread running...

Worker thread running...

Main stopping thread

Worker closing down

Now that we know how to stop a custom function running in a new thread, let’s look at an example of stopping a custom thread class.

Example of Stopping a Thread With an Extended Class

In this section we can explore how to stop a thread that is an object that extends the threading.Thread class.

First, we will develop an example that extends the threading.Thread class, then we will look at how to update the example to stop the thread on demand.

Custom Thread Class

We can run a task in a new thread by extending the threading.Thread class and overriding the constructor and the run() function.

In this section, we will show how to run the same task as in the previous section within a custom thread class.

Firstly, we can define a new class that extends threading.Thread.

# custom thread class

classCustomThread(Thread):

# ...

The new class must implement a constructor and call the constructor of the threading.Thread class to properly initialize the underlying thread instance.

# constructor

def __init__(self):

    # call the parent constructor

    super(CustomThread,self).__init__()

We can then override the run() method on the threading.Thread class.

This function will run in a new thread once the thread is started via the start() function. Specifically we call start() and start() will call run() for us in a new thread of execution.

Our task will be to execute a loop five times, block for a second to simulate work, and report a message. Then report a message once the task is complete.

# execute task

def run(self):

    # execute a task in a loop

    foriinrange(5):

        # block for a moment

        sleep(1)

        # report a message

        print('Worker thread running...')

    print('Worker closing down')

Tying this together the new CustomThread class is listed below.

# custom thread class

classCustomThread(Thread):

    # constructor

    def __init__(self):

        # call the parent constructor

        super(CustomThread,self).__init__()

    # execute task

    def run(self):

        # execute a task in a loop

        foriinrange(5):

            # block for a moment

            sleep(1)

            # report a message

            print('Worker thread running...')

        print('Worker closing down')

Next, in the main thread, we can create a new instance of our custom thread class and start it in order to execute our task in a new thread.

...

# create a new thread

thread=CustomThread()

# start the new thread

thread.start()

We will then join() the new thread and wait for the new thread to terminate, before terminating the main thread.

...

# wait for the new thread to finish

thread.join()

Tying this together, the complete example is listed below.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

# SuperFastPython.com

# example of a extending the thread class

from time import sleep

from threading import Thread

# custom thread class

classCustomThread(Thread):

    # constructor

    def __init__(self):

        # call the parent constructor

        super(CustomThread, self).__init__()

    # execute task

    def run(self):

        # execute a task in a loop

        for iinrange(5):

            # block for a moment

            sleep(1)

            # report a message

            print('Worker thread running...')

        print('Worker closing down')

# create a new thread

thread= CustomThread()

# start the new thread

thread.start()

# wait for the new thread to finish

thread.join()

Running the example first creates our custom thread class then starts executing the new thread.

The main thread then blocks waiting for the new thread to finish.

Our custom thread class runs our task in a new thread of execution, looping five times. Each iteration it blocks for a moment then reports a message.

Once the task is finished, it reports a final message.

The new thread terminates, then the main thread terminates, closing the process.

Worker thread running...

Worker thread running...

Worker thread running...

Worker thread running...

Worker thread running...

Worker closing down

Next, let’s look at how we might update this example to stop the task on demand.

Stop Custom Thread Class

We can update the example in the previous section to stop the thread on demand.

This can be achieved by sharing a threading.Event with the new thread and updating the run() function to check if the event is set each iteration. Once set, the run() function can exit, which will terminate the new thread.

Firstly, we can update the constructor of our new thread class to take the shared threading.Event as an argument and then store it as a member variable.

# constructor

def __init__(self,event):

    # call the parent constructor

    super(CustomThread,self).__init__()

    # store the event

    self.event=event

Next, we can update the run() function to check the status of the threading.Event each iteration and to break the task loop once the event is set.

# execute task

def run(self):

    # execute a task in a loop

    foriinrange(5):

        # block for a moment

        sleep(1)

        # check for stop

        ifself.event.is_set():

            break

        # report a message

        print('Worker thread running...')

    print('Worker closing down')

Tying this together, the updated CustomThread class that can be stopped on demand is listed below.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

# custom thread class

classCustomThread(Thread):

    # constructor

    def __init__(self,event):

        # call the parent constructor

        super(CustomThread,self).__init__()

        # store the event

        self.event =event

    # execute task

    def run(self):

        # execute a task in a loop

        fori inrange(5):

            # block for a moment

            sleep(1)

            # check for stop

            ifself.event.is_set():

                break

            # report a message

            print('Worker thread running...')

        print('Worker closing down')

In the main thread, we must first create an instance of an event that can be shared between threads.

...

# create the event

event=Event()

We must then pass it to the constructor of our new CustomThread class.

...

# create a new thread

thread=CustomThread(event)

We can then update the new thread to block for a few seconds, then request that the new thread terminate by setting the event.

...

# block for a while

sleep(3)

# stop the worker thread

print('Main stopping thread')

event.set()

Finally, the main thread will wait for the new thread to terminate.

...

# wait for the new thread to finish

thread.join()

Tying this together, the complete example is listed below.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

# SuperFastPython.com

# example of stopping a custom thread class

from time import sleep

from threading import Thread

from threading import Event

# custom thread class

class CustomThread(Thread):

    # constructor

    def __init__(self,event):

        # call the parent constructor

        super(CustomThread, self).__init__()

        # store the event

        self.event=event

    # execute task

    def run(self):

        # execute a task in a loop

        foriinrange(5):

            # block for a moment

            sleep(1)

            # check for stop

            if self.event.is_set():

                break

            # report a message

            print('Worker thread running...')

        print('Worker closing down')

# create the event

event=Event()

# create a new thread

thread= CustomThread(event)

# start the new thread

thread.start()

# block for a while

sleep(3)

# stop the worker thread

print('Main stopping thread')

event.set()

# wait for the new thread to finish

thread.join()

Running the example first involves creating an instance of the custom thread and starting it.

The main thread will then block for a few seconds.

The new thread will start executing its task loop, blocking for a moment and reporting progress.

The main thread then wakes up and sets the event, triggering the new thread to stop.

The new thread notices that the event is set and then exits the task loop, reporting a final message and terminating the new thread.

The main thread waits for the new thread to terminate, before then stopping itself and closing the application.

Worker thread running...

Worker thread running...

Main stopping thread

Worker closing down

Common Questions About Stopping Threads

This section lists common questions about stopping a new thread in Python.

Do you have any questions about stopping a new thread? Let me know in the comments and I will do my best to help.

What if My Task Does Not Have a Loop?

Your task does not need to have a loop in order to be stopped.

Instead, you need to add frequent checks of the shared threading.Event and return from the task() function or run() function once the event is set.

This will depend on the specifics of the task you wish to exit in a new thread.

If your task involves blocking, such as reading or writing IO or waiting on another thread, you may want to adopt a busy wait and have the threading.Event checked each iteration.

You can learn more about implementing a busy wait here:

  • How to Use Busy Waiting in Python

If your task remains idle for some time, such as waiting for sporadic events, it may be able to wait on the threading.Event itself via the wait() function.

What if My Task Raises An Exception?

If your task executing in a new thread raises an exception that is not handled, it will terminate the thread.

This could be an alternate way for you to trigger a new thread to terminate, if convenient.

What if My New Thread Has Already Stopped?

If the new thread has already stopped and you set the event, it will not have any effect.

It would not be a problem.

What if My New Thread is a Daemon Thread?

If your task is executing in a daemon thread, then there is no need to stop it manually as it will be terminated for you once all non-daemon threads (e.g. the main thread) terminate.

You can learn more about daemon threads here:

  • How to Use Daemon Threads in Python

If you want to manually stop your daemon thread, you can use the same method as above.

You can see an example of this here:

  • How to Stop a Daemon Thread Gracefully in Python

How Can We Stop Multiple Threads?

You can share the same threading.Event between all of the threads that might want to stop.

Each thread can frequently check the status of the event.

Once set, all threads can exit their task and terminate.

How Can We Stop Daemon Threads?

The same technique of using a threading.Event can be used to stop daemon threads.

You can see an example of this here:

  • How to Stop a Daemon Thread Gracefully in Python

How Can We Stop Tasks in a ThreadPoolExecutor?

The same technique of using a threading.Event can be used to stop tasks executing in a ThreadPoolExecutor.

You can see an example of this here:

  • How To Stop Running Tasks in the ThreadPoolExecutor in Python

Further Reading

This section provides additional resources that you may find helpful.

  • threading - Thread-based parallelism
  • Threading: The Complete Guide
  • Threading Module API Cheat Sheet
  • Threading API Interview Questions
  • Threading Jump-Start (my 7-day course)

Takeaways

You now know how to stop a thread in Python.

Do you have any questions?
Ask your questions in the comments below and I will do my best to answer.

Photo by Leon Seierlein on Unsplash