• python多线程编程: 如何暴力但不失优雅地关闭线程


    问题需求

    多i线程编程中,常常遇到的1个头痛问题是,主线程退出后,子线程未能正常退出,造成一些数据丢失,文件破坏的隐患,或者成为僵尸进程,占用系统资源
    前面文章介绍了几种优雅关闭线程的方法,但也有一些网友提出疑问:是否可以暴力但不留隐患杀死线程?, 答案是:Yes!

    Python其它关闭线程的方法,请参阅本人博文 Python多线程编程:如何优雅地关闭线程

    暴力但不失优雅地关闭线程的解决方法

    1、解决方法说明

    1)所谓暴力就是按 Ctrl+C, 或者 Linux下发送kill -9 强制中止程序信号等。
    2)通过python内置signal模块,实时捕捉到Ctrl+C信号,并触发回调函数。
    3)为了让代码更健壮,在回调函中抛出了1个自定义异常类,在主线程中捕获到该异常后,通过设置event对象安全地关闭线程。

    2、完整代码

    下面是完整代码,在win10下测试,支持按 Ctrl+C键, 或者通过任务面板关闭进程,均可安全地关闭线程,杜绝隐患。
    Linux系统下,将信号 signal.SIGTERM 改为 signal.SIGKILL即可,可用kill -9 命令直接杀死线程。

    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()
    
    
    • 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
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    运行output 如下

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    攻防千层饼
    什么是同源策略?
    AI智能分析网关V4智慧环保/智慧垃圾站视频智能分析与监控方案
    web3.0入门及学习路径
    [山东科技大学OJ]1897 Problem E: 编写函数:递归的字符串回文 (Append Code)
    众望所归,FoxPro之后,可视化编程再现新突破,国产力作
    Java案例——控制台实现QuickHit小游戏
    Vue安装和环境配置
    【LeetCode算法系列题解】第46~50题
    基于自适应启动策略的混合交叉动态约束多目标优化算法(MC-DCMOEA)求解CEC2015/CEC2018/CEC2023(MATLAB代码)
  • 原文地址:https://blog.csdn.net/captain5339/article/details/132768835