Is there a way to kill a thread in Python?

1

Is there any way to stop a thread in python? And is it a bad practice to do this?

    
asked by anonymous 20.10.2015 / 02:32

1 answer

0

It is a bad practice to abruptly stop a thread in any language.

Let's think The thread has some critical feature that needs to be closed properly. The thread has other threads that must be paused along with this thread.

The best way to handle this if you can, (if you are administering your own threads) is to have an exit_request flag that each thread checks regularly to see if it is time to close.

Let's take an example:

import threading

class StoppableThread(threading.Thread):
    """Thread class com metodo de stop(). A thread precisa checar 
    regularmente pela condição de stopped() ."""

    def __init__(self):
        super(StoppableThread, self).__init__()
        self._stop = threading.Event()

    def stop(self):
        self._stop.set()

    def stopped(self):
        return self._stop.isSet()

There are cases, however, when you really need to kill a thread. An example is when you are wrapping an external library that is busy and you want to stop it.

The following example allows (with some restrictions) to throw an exception on a Python thread:

def _async_raise(tid, exctype):
    '''Lanca uma excecao na threads com id tid'''
    if not inspect.isclass(exctype):
        raise TypeError("Somente tipos podem ser lancados (nao instancias)")
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
                                                  ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("thread com invalido id")
    elif res != 1:
        # "Se lancar um numero maior que um, eh um problema,
        # e voce deveria chamar novamente com exc=NULL para reverter o efeito"
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
        raise SystemError("PyThreadState_SetAsyncExc falhou")

class ThreadWithExc(threading.Thread):
    def _get_my_tid(self):
        if not self.isAlive():
            raise threading.ThreadError("the thread is not active")

        if hasattr(self, "_thread_id"):
            return self._thread_id

        for tid, tobj in threading._active.items():
            if tobj is self:
                self._thread_id = tid
                return tid

        # TODO: em python 2.6, existe uma forma mais simples : self.ident

        raise AssertionError("nao pode determinar as threads com id")

    def raiseExc(self, exctype):
        _async_raise( self._get_my_tid(), exctype )

As noted, this is not perfect, because if the thread is busy outside the Python interpreter, it will not catch the interrupt.

    
20.10.2015 / 02:38