Как остановить поток в python
Перейти к содержимому

Как остановить поток в python

  • автор:

Sanix-Darker / [PYTHON]Kill_thread.md

In general, killing threads abruptly is considered a bad programming practice. Killing a thread abruptly might leave a critical resource that must be closed properly, open. But you might want to kill a thread once some specific time period has passed or some interrupt has been generated. There are the various methods by which you can kill a thread in python.

  • Raising exceptions in a python thread
  • Set/Reset stop flag
  • Using traces to kill threads
  • Using the multiprocessing module to kill threads
  • Killing Python thread by setting it as daemon
  • Using a hidden function _stop()

Raising exceptions in a python thread :

This method uses the function PyThreadState_SetAsyncExc() to raise an exception in the a thread. For Example,

When we run the code above in a machine and you will notice, as soon as the function raise_exception() is called, the target function run() ends. This is because as soon as an exception is raised, program control jumps out of the try block and run() function is terminated. After that join() function can be called to kill the thread. In the absence of the function run_exception(), the target function run() keeps running forever and join() function is never called to kill the thread.

Set/Reset stop flag :

In order to kill a threads, we can declare a stop flag and this flag will be check occasionally by the thread. For Example

In the above code, as soon as the global variable stop_threads is set, the target function run() ends and the thread t1 can be killed by using t1.join(). But one may refrain from using global variable due to certain reasons. For those situations, function objects can be passed to provide a similar functionality as shown below.

The function object passed in the above code always returns the value of the local variable stop_threads. This value is checked in the function run(), and as soon as stop_threads is reset, the run() function ends and the thread can be killed.

Using traces to kill threads :

This methods works by installing traces in each thread. Each trace terminates itself on the detection of some stimulus or flag, thus instantly killing the associated thread. For Example

In this code, start() is slightly modified to set the system trace function using settrace(). The local trace function is defined such that, whenever the kill flag (killed) of the respective thread is set, a SystemExit exception is raised upon the excution of the next line of code, which end the execution of the target function func. Now the thread can be killed with join().

Using the multiprocessing module to kill threads :

The multiprocessing module of Python allows you to spawn processes in the similar way you spawn threads using the threading module. The interface of the multithreading module is similar to that of the threading module. For Example, in a given code we created three threads(processes) which count from 1 to 9.

The functionality of the above code can also be implemented by using the multiprocessing module in a similar manner, with very few changes. See the code given below.

Though the interface of the two modules is similar, the two modules have very different implementations. All the threads share global variables, whereas processes are completely separate from each other. Hence, killing processes is much safer as compared to killing threads. The Process class is provided a method, terminate(), to kill a process. Now, getting back to the initial problem. Suppose in the above code, we want to kill all the processes after 0.03s have passed. This functionality is achieved using the multiprocessing module in the following code.

Though the two modules have different implementations. This functionality provided by the multiprocessing module in the above code is similar to killing threads. Hence, the multiprocessing module can be used as a simple alternative whenever we are required to implement the killing of threads in Python.

Killing Python thread by setting it as daemon :

Daemon threads are those threads which are killed when the main program exits. For Example

Notice that, thread t1 stays alive and prevents the main program to exit via sys.exit(). In Python, any alive non-daemon thread blocks the main program to exit. Whereas, daemon threads themselves are killed as soon as the main program exits. In other words, as soon as the main program exits, all the daemon threads are killed. To declare a thread as daemon, we set the keyword argument, daemon as True. For Example in the given code it demonstrates the property of daemon threads.

Notice that, as soon as the main program exits, the thread t1 is killed. This method proves to be extremely useful in cases where program termination can be used to trigger the killing of threads. Note that in Python, the main program terminates as soon as all the non-daemon threads are dead, irrespective of the number of daemon threads alive. Hence, the resources held by these daemon threads, such as open files, database transactions, etc. may not be released properly. The initial thread of control in a python program is not a daemon thread. Killing a thread forcibly is not recommended unless it is known for sure, that doing so will not cause any leaks or deadlocks.

Using a hidden function _stop() :

In order to kill a thread, we use hidden function _stop() this function is not documented but might disappear in the next version of python.

Note: Above methods might not work in some situation or another, because python does not provide any direct method to kill threads.

How to Stop a Thread in Python

Summary: in this tutorial, you’ll learn how to stop a thread in Python from the main thread using the Event class of the threading module.

Introduction to the Event object

To stop a thread, you use the Event class of the threading module. The Event class has an internal thread-safe boolean flag that can be set to True or False . By default, the internal flag is False .

In the Event class, the set() method sets the internal flag to True while the clear() method resets the flag to False . Also, the is_set() method returns True if the internal flag is set to True .

To stop a child thread from the main thread, you use an Event object with the following steps:

  • First, create a new Event object and pass it to a child thread.
  • Second, periodically check if the internal flag of the Event object is set in the child thread by calling the is_set() method and stop the child thread if the internal flag was set.
  • Third, call the set() method in the main thread at some point in time to stop the child thread.

The following flow chart illustrates the above steps:

python stop thread

A simple example of stopping a thread in Python

The following example shows how to use an Event object to stop a child thread from the main thread:

The task() function

The task() function uses an Event object and returns None . It will be executed in a child thread:

The task() function iterates over the numbers from 1 to 5. In each iteration, we use the sleep() function to delay the execution and exit the loop if the internal flag of the event object is set.

The main() function

First, create a new Event object:

Next, create a new thread that executes the task() function with an argument as the Event object:

Then, start executing the child thread:

After that, suspend the main thread for three seconds:

Finally, set the internal flag of the Event object to True by calling the set() method. This will also stop the child thread:

Stopping a thread that uses a child class of the Thread class

Sometimes, you may want to extend the Thread class and override the run() method for creating a new thread:

To stop the thread that uses a derived class of the Thread class, you also use the Event object of the threading module.

The following example shows how to create a child thread using a derived class of the Thread class and uses the Event object to stop the child thread from the main thread in demand:

First, define a Worker class that extends the Thread class from the threading module. The __init__() method of the Worker class accepts an Event object.

Second, override the run() method of the Worker class and use the event object to stop the thread.

Third, define the main() function that creates an event, a Worker thread, and passes the event object to the Worker thread. The remaining logic is the same as the main() function in the previous example.

Как остановить поток в python

In general, killing threads abruptly is considered a bad programming practice. Killing a thread abruptly might leave a critical resource that must be closed properly, open. But you might want to kill a thread once some specific time period has passed or some interrupt has been generated. There are the various methods by which you can kill a thread in python.

  • Raising exceptions in a python thread
  • Set/Reset stop flag
  • Using traces to kill threads
  • Using the multiprocessing module to kill threads
  • Killing Python thread by setting it as daemon
  • Using a hidden function _stop()

Raising exceptions in a python thread :
This method uses the function PyThreadState_SetAsyncExc() to raise an exception in the a thread. For Example,

Python3

When we run the code above in a machine and you will notice, as soon as the function raise_exception() is called, the target function run() ends. This is because as soon as an exception is raised, program control jumps out of the try block and run() function is terminated. After that join() function can be called to kill the thread. In the absence of the function run_exception(), the target function run() keeps running forever and join() function is never called to kill the thread.

Set/Reset stop flag :
In order to kill a threads, we can declare a stop flag and this flag will be check occasionally by the thread. For Example

Python3

In the above code, as soon as the global variable stop_threads is set, the target function run() ends and the thread t1 can be killed by using t1.join(). But one may refrain from using global variable due to certain reasons. For those situations, function objects can be passed to provide a similar functionality as shown below.

Python3

The function object passed in the above code always returns the value of the local variable stop_threads. This value is checked in the function run(), and as soon as stop_threads is reset, the run() function ends and the thread can be killed.

Using traces to kill threads :
This methods works by installing traces in each thread. Each trace terminates itself on the detection of some stimulus or flag, thus instantly killing the associated thread. For Example

Python3

In this code, start() is slightly modified to set the system trace function using settrace(). The local trace function is defined such that, whenever the kill flag (killed) of the respective thread is set, a SystemExit exception is raised upon the execution of the next line of code, which end the execution of the target function func. Now the thread can be killed with join().

Using the multiprocessing module to kill threads :
The multiprocessing module of Python allows you to spawn processes in the similar way you spawn threads using the threading module. The interface of the multithreading module is similar to that of the threading module. For Example, in a given code we created three threads(processes) which count from 1 to 9.

Python3

The functionality of the above code can also be implemented by using the multiprocessing module in a similar manner, with very few changes. See the code given below.

Python3

Though the interface of the two modules is similar, the two modules have very different implementations. All the threads share global variables, whereas processes are completely separate from each other. Hence, killing processes is much safer as compared to killing threads. The Process class is provided a method, terminate(), to kill a process. Now, getting back to the initial problem. Suppose in the above code, we want to kill all the processes after 0.03s have passed. This functionality is achieved using the multiprocessing module in the following code.

Python3

Though the two modules have different implementations. This functionality provided by the multiprocessing module in the above code is similar to killing threads. Hence, the multiprocessing module can be used as a simple alternative whenever we are required to implement the killing of threads in Python.

Killing Python thread by setting it as daemon :
Daemon threads are those threads which are killed when the main program exits. For Example

Python3

Notice that, thread t1 stays alive and prevents the main program to exit via sys.exit(). In Python, any alive non-daemon thread blocks the main program to exit. Whereas, daemon threads themselves are killed as soon as the main program exits. In other words, as soon as the main program exits, all the daemon threads are killed. To declare a thread as daemon, we set the keyword argument, daemon as True. For Example in the given code it demonstrates the property of daemon threads.

Python3

Notice that, as soon as the main program exits, the thread t1 is killed. This method proves to be extremely useful in cases where program termination can be used to trigger the killing of threads. Note that in Python, the main program terminates as soon as all the non-daemon threads are dead, irrespective of the number of daemon threads alive. Hence, the resources held by these daemon threads, such as open files, database transactions, etc. may not be released properly. The initial thread of control in a python program is not a daemon thread. Killing a thread forcibly is not recommended unless it is known for sure, that doing so will not cause any leaks or deadlocks.
Using a hidden function _stop() :
In order to kill a thread, we use hidden function _stop() this function is not documented but might disappear in the next version of python.

How to stop a Python thread cleanly

Suppose a Python thread needs to be stopped cleanly (it might need to perform cleanup).

For illustration, we will take a very simple program in with a single “worker” thread that displays a message when it is done. The message is a placeholder for real cleanup, and the thread itself sleeps for a given number of iterations (as a placeholder for significant work). In our example, we want to stop the thread through a keyboard interrupt (Ctrl + C).

By default, the thread is not stopped cleanly

In this first version, the program can be stopped by hitting Ctrl + C, but the thread keeps running. Here is the program:

Here is what happens when stopping it via a keyboard interrupt ( . denotes output that was snipped for readability purposes):

The first Ctrl + C stops the main program, but not the thread. The second time, the thread is stopped as well.

Using a daemon thread is not a good idea

The Python threading documentation explains that a thread may be started as a daemon, meaning that “the entire Python program exits when only daemon threads are left”. The main program itself is not a daemon thread.

While this approach has the merit of effectively stopping the thread, it does not allow to exit it cleanly. From the Python documentation:

Note: Daemon threads are abruptly stopped at shutdown. Their resources (such as open files, database transactions, etc.) may not be released properly. If you want your threads to stop gracefully, make them non-daemonic and use a suitable signalling mechanism such as an Event .

A clean thread exit using events and signals

Following on the previous note, a threading Event is a simple object that can be set or cleared. It can be used to signal to the thread that it needs perform its cleanup and then stop.

The idea is to use such an event here (let us call it a stop event). Initially not set, the stop event becomes set when a keyboard interrupt is received. The worker thread then breaks out from the loop if the stop event is set and performs its cleanup.

Creating the stop event is straightforward (it can take any name):

The worker thread checks whether the stop event is set:

The stop event needs to be set when a keyboard interrupt is intercepted. This is done by registering the SIGINT signal with a handler function. The registration is done in the main program:

The handler function handle_kb_interrupt must have two arguments, the signal and the frame, even though the second argument is not used:

Here is the full program:

Here is the output when hitting Ctrl + C in the new version of the program:

Notice that when the thread is stopped it now finally gets to the print(‘Thread done’) line (a placeholder for an actual cleanup task). Moreover, the main program also gets to the print(‘Program done’) line. Clean exit from a thread can therefore be achieved using a threading event and a signal handler.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *