views:

11387

answers:

6

Is it possible to terminate a running thread without setting/checking any flags/semaphores/etc.?

+9  A: 

You should never forcibly kill a thread without cooperating with it.

Killing a thread removes any guarantees that try/finally blocks set up so you might leave locks locked, files open, etc.

The only time you can argue that forcibly killing threads is a good idea is to kill a program fast, but never single threads.

Lasse V. Karlsen
+9  A: 

There is no official API to do that, no.

You need to use platform API to kill the thread, e.g. pthread_kill, or TerminateThread. You can access such API e.g. through pythonwin, or through ctypes.

Notice that this is inherently unsafe. It will likely lead to uncollectable garbage (from local variables of the stack frames that become garbage), and may lead to deadlocks, if the thread being killed has the GIL at the point when it is killed.

Martin v. Löwis
+6  A: 

It is better if you don't kill a thread. A way could be to introduce a "try" block into the thread's cycle and to throw an exception when you want to stop the thread (for example a break/return/... that stops your for/while/...). I've used this on my app and it works...

Giancarlo
+3  A: 

You can kill a thread by installing trace into the thread that will exit the thread. See attached link for one possible implementation.

Kill a thread in Python

Kozyarchuk
I've already seen it. This solution is based on self.killed flag check
Sudden Def
Are you sure about that link? For me it points to 'GetClipboardData(CF_BITMAP) unimplemented'
David Sykes
+26  A: 

It is generally a bad pattern to kill a thread abruptly, in python and in any language. Think of the following cases:

  • the thread is holding a critical resource that must be closed properly
  • the thread has created several other threads that must be killed as well.

The nice way of handling this if you can afford it (if you are managing your own threads) is to have an exit_request flag that each threads checks on regular interval to see if it is time for him to exit.

For example:

class StoppableThread (threading.Thread):
    """Thread class with a stop() method. The thread itself has to check
    regularly for the stopped() condition."""

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

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

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

In this code, you should call stop() on the thread when you want it to exit, and wait for the thread to exit properly using join(). The thread should check the stop flag at regular intervals.

They are cases however when you really need to kill a thread, for example when you are wrapping an external library that is busy for long calls and you want to interrupt it.

The following code allows (with some restrictions) to raise an Exception in a python thread:

def _async_raise(tid, exctype):
    '''Raises an exception in the threads with id tid'''
    if not inspect.isclass(exctype):
        raise TypeError("Only types can be raised (not instances)")
    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, 0)
        raise SystemError("PyThreadState_SetAsyncExc failed")


class ThreadWithExc(threading.Thread):
    '''A thread class that supports raising exception in the thread from another thread.
    '''
    def _get_my_tid(self):
        """determines this (self's) thread id

        CAREFUL : this function is executed in the context of the caller thread,
        to get the identity of the thread represented by this instance.
        """
        if not self.isAlive():
            raise threading.ThreadError("the thread is not active")

        # do we have it cached?
        if hasattr(self, "_thread_id"):
            return self._thread_id

        # no, look for it in the _active dict
        for tid, tobj in threading._active.items():
            if tobj is self:
                self._thread_id = tid
                return tid

        # TODO : in python 2.6, there's a simpler way to do : self.ident ...

        raise AssertionError("could not determine the thread's id")

    def raiseExc(self, exctype):
        """Raises the given exception type in the context of this thread.

        If the thread is busy in a system call (time.sleep(), socket.accept(), ...) the exception
        is simply ignored.

        If you are sure that your exception should terminate the thread, one way to ensure that
        it works is:
        t = ThreadWithExc( ... )
        ...
        t.raiseExc( SomeException )
        while t.isAlive():
            time.sleep( 0.1 )
            t.raiseExc( SomeException )

        If the exception is to be caught by the thread, you need a way to check that your
        thread has caught it.

        CAREFUL : this function is executed in the context of the caller thread,
        to raise an excpetion in the context of the thread represented by this instance.
        """
        _async_raise( self._get_my_tid(), exctype )

As noted in the documentation, this is not a magic bullet because if the thread is busy outside the python interpreter, it will not catch the interruption.

A good usage pattern of this code is to have the thread catch a specific exception and perform the cleanup. That way, you can interrupt a task and still have proper cleanup.

Bluebird75
I've already done something like this, but thanks anyway
Sudden Def
+4  A: 

If you are trying to terminate the whole program you can set the thread as a "daemon". see Thread.daemon

schettino72
very useful info, that's exactly what I was looking for.
UncleZeiv