Python multi-threaded programming: How to shut down threads violently but gracefully

Problem requirements

In multi-thread programming, a common headache problem is that after the main thread exits, the child thread fails to exit normally, causing some data loss, file damage, or becoming a zombie process and occupying system resources.
The previous article introduced several methods of closing threads gracefully, but some netizens also raised questions: Is it possible to kill threads violently without leaving hidden dangers? , the answer is: Yes!

For other methods of closing threads in Python, please refer to my blog post Python Multithreaded Programming: How to Close Threads Gracefully

A solution to shut down threads violently but gracefully

1. Solution description

1) The so-called violence means pressing , or sending a forced termination signal Ctrl+Cunder Linux , etc. 2) Through the python module, you can capture the Ctrl+C signal in real time and trigger the callback function. Set the switch variable to off, execute clean code, and then close the thread. 3) In order to make the code more robust, a custom exception class is used to be responsible for the exit of the main thread.kill -9
signal

2. Complete code

The following is the complete code. It was tested under win10. It supports pressing Ctrl+C keys or closing the process through the task panel to safely close the thread and eliminate hidden dangers.
Under the Linux system, just signal.SIGTERMchange the signal to signal.SIGKILL, and you can use kill -9 the command to kill the thread directly.

from math import e
import time
import threading
import signal
 
 
class Task(threading.Thread):
 
    def __init__(self):
        threading.Thread.__init__(self)
 
        # shutdown_flag 用于关闭线程
        self.shutdown_flag = threading.Event()
 
        # ... Other thread setup code here ...
 
    def run(self):
        print(f'Thread #{
      
      self.ident} started')
 
        while not self.shutdown_flag.is_set():
            # 线程代码可以放在这里            
            print(f"Thread #{
      
      self.ident} is running...")
            time.sleep(1)
 
        # ... Clean code put here ...
        print(f'Thread #{
      
      self.ident} stopped')
 
 
class ServiceExit(Exception):
    """
    自定义1个异常类,用于退出线程
    """
    def __init__(self,message="force to quit"):
        self.message = message
        super(ServiceExit,self).__init__(self.message)
    
    # __str__ is to print() the message
    def __str__(self):
        return(repr(self.message))
 
 
def handler_quit(signum, frame):
    """信号处理函数"""
    print('Caught signal %d' % signum)
    raise ServiceExit("当前线程被强制退出...")
 
 
def main():
 
    # 注册信号回调函数
    signal.signal(signal.SIGTERM, handler_quit)
    signal.signal(signal.SIGINT, handler_quit)
 
    print('Starting main program')
 
    # Start the sub threads
    try:
        t1 = Task()
        t2 = Task()
        t1.start()
        t2.start()
 
        # 保持主线程运行,否则无法收到信号
        while True:
            time.sleep(0.5)
 
    except ServiceExit as e:
        t1.shutdown_flag.set()
        t2.shutdown_flag.set()
        # Wait for the threads to close...
        t1.join()
        t2.join()
        print(e.message)
 
    print('Exiting main program')
 
 
if __name__ == '__main__':
    main()

Run output as follows

Starting main program
Thread #119072 started
Thread #119072 is running...
Thread #119076 started
Thread #119076 is running...
Thread #119076 is running...
Thread #119072 is running...
Thread #119072 is running...
Thread #119076 is running...
Thread #119076 is running...
Thread #119072 is running...
Caught signal 2
Thread #119072 stopped
Thread #119076 stopped
当前线程被强制退出...
Exiting main program

Guess you like

Origin blog.csdn.net/captain5339/article/details/132768835