This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
wujiating-diamondv/util/thread_timeout.py

66 lines
1.9 KiB
Python
Raw Normal View History

2022-05-19 14:55:02 +08:00
from threading import Thread
import inspect
import ctypes
from functools import wraps
def _async_raise(tid, exctype):
"""raises the exception, performs cleanup if needed"""
tid = ctypes.c_long(tid)
if not inspect.isclass(exctype):
exctype = type(exctype)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
if res == 0:
raise ValueError("invalid thread id")
elif res != 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
raise SystemError("PyThreadState_SetAsyncExc failed")
def stop_thread(thread):
_async_raise(thread.ident, SystemExit)
class TimeoutException(Exception):
# print("timeout!")
pass
ThreadStop = stop_thread
def time_limited(timeout):
def decorator(function):
@wraps(function)
def wrapped_function(*args, **kwargs):
class TimeLimited(Thread):
def __init__(self):
Thread.__init__(self)
self.error = None
self.result = None
def run(self):
self.result = function(*args, **kwargs)
def stop(self):
if self.is_alive():
ThreadStop(self)
t = TimeLimited()
t.start()
t.join(timeout)
if isinstance(t.error, TimeoutException):
t.stop()
raise TimeoutException('timeout for %s' % (repr(function)))
if t.is_alive():
t.stop()
raise TimeoutException('timeout for %s' % (repr(function)))
if t.error is None:
return t.result
return wrapped_function
return decorator