Python线程死锁不退出,最长运行时间设置TTL, 线程超时杀死线程

import threading
import time
import inspect
import ctypes
from queue import Queue


class ThreadTTLMonitor(threading.Thread):
    def __init__(self, threads, ttl=600, delay=0.1, **kwargs):
        threading.Thread.__init__(self, **kwargs)
        self.setDaemon(True)
        self._threads = threads
        self.delay = delay
        self.name = 'ThreadMonitor'
        #
        self._thread_timer_queue = Queue()
        for thread in threads:
            self._thread_timer_queue.put({'thread': thread, 'ttl': ttl})
        #
        self._dismissed = threading.Event()
        self.start()

    def create_monitor(self, thread, ttl=600):
        self._thread_timer_queue.put({'thread': thread, 'ttl': ttl})

    @staticmethod
    def _async_raise(thread_id, exc_type):
        """raises the exception, performs cleanup if needed"""
        thread_id = ctypes.c_long(thread_id)
        if not inspect.isclass(exc_type):
            exc_type = type(exc_type)
        res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(exc_type))
        if res == 0:
            raise Exception("invalid thread id")
        elif res != 1:
            ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, None)
            raise Exception("PyThreadState_SetAsyncExc failed")

    @classmethod
    def stop_thread(cls, thread):
        if not thread.is_alive():
            return
        cls._async_raise(thread.ident, Exception)

    def dismiss(self):
        """Sets a flag to tell the thread to exit when done with current job.
        """
        self._dismissed.set()

    def run(self):
        while True:
            try:
                if self._dismissed.isSet():
                    break
                item = self._thread_timer_queue.get()
                if not item:
                    time.sleep(self.delay)
                    continue
                thread = item.get('thread')
                ttl = item.get('ttl')
                ttl -= self.delay
                if ttl <= 0:
                    self.stop_thread(thread)
                    continue
                item.update(ttl=ttl)
                self._thread_timer_queue.put(item)
            except Exception as e:
                raise e
            time.sleep(self.delay)

 

posted @ 2021-03-05 11:36  士为知己  阅读(788)  评论(0)    收藏  举报