code: def _lowlevel_async_raise(thread_obj, exception=None):
      NULL = 0  # noqa
      found = False
      target_tid = 0
      for tid, tobj in threading._active.items():  # noqa
          if tobj is thread_obj:
              found = True
              target_tid = tid
              break
  
      if not found:
          # raise ValueError("Invalid thread object")
          return False
  
      if not exception:
          exception = SystemExit()
  
      if sys.version_info.major >= 3 and sys.version_info.minor >= 7:
          target_tid = ctypes.c_ulong(target_tid)
          NULL = ctypes.c_ulong(NULL)  # noqa
      else:
          target_tid = ctypes.c_long(target_tid)
          NULL = ctypes.c_long(NULL)  # noqa
  
      # noinspection PyBroadException
      try:
          ret = ctypes.pythonapi.PyThreadState_SetAsyncExc(
              target_tid, ctypes.py_object(exception)
          )
      except Exception:
          ret = 0
  
      # ref: http://docs.python.org/c-api/init.html#PyThreadState_SetAsyncExc
      if ret == 0:
          # raise ValueError("Invalid thread ID")
          return False
      elif ret > 1:
          # Huh? Why would we notify more than one threads?
          # Because we punch a hole into C level interpreter.
          # So it is better to clean up the mess.
          # noinspection PyBroadException
          try:
              ctypes.pythonapi.PyThreadState_SetAsyncExc(
                  target_tid, NULL
              )
          except Exception:
              pass
          # raise SystemError("PyThreadState_SetAsyncExc failed")
          return False
  
      # print("Successfully set asynchronized exception for", target_tid)
      return True
  
file_path: clearml/clearml/utilities/lowlevel/threads.py
imports: import ctypes
  import threading
  import six
  import sys
  import time
label_desc: Use image node_id 2 for calling a global function with example usage: _lowlevel_async_raise(thread_obj, exception) and returns: True, False, False, False