thread, threading; how to kill a thread?

David Bolen db3l at fitlinxx.com
Wed Nov 17 17:34:27 EST 2004


Ian Bicking <ianb at colorstudy.com> writes:

> It's more, "yes, I know the answer, but I remain unsatisfied".  I'm
> 100% okay with a platform-specific way to accomplish this (especially
> if the platform is Linux and BSD).  I'm okay with horrid hacks, or
> memory leaks, or other possible compromises.  But I'm not really okay
> with the standard answer.  And so I'm hoping someone else felt the
> same way and figured something out...?

I'm not familiar enough with pthreads to guess there, but under
Windows, you can technically accomplish what you want using
TerminateThread.  Perhaps there is a similar flow that could be used
with pthreads.

My major concern though in any attempt to externally kill off a thread
would be that you somehow strand the interpreter with that dead thread
still owning the GIL.  There's plenty of other sorts of system
resources that could also be stranded (at least until process exit),
but killing off the GIL owner would definitely mess up the
application's day.

As a sample, the following works under Windows:

          - - - - - - - - - - - - - - - - - - - - - - - - -

import threading
import ctypes
import time

w32 = ctypes.windll.kernel32
THREAD_TERMINATE = 1    # Privilege level for termination

class DummyThread(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        self.setDaemon(1)

    def run(self):
        self.tid = w32.GetCurrentThreadId()

        while 1:
            print 'Running'
            time.sleep(1)

def kill_thread(threadobj):

    handle = w32.OpenThread(THREAD_TERMINATE, False, threadobj.tid)
    result = w32.TerminateThread(handle, 0)
    w32.CloseHandle(handle)

    return result

if __name__ == "__main__":

    print 'Starting thread...'
    x = DummyThread()
    x.start()

    time.sleep(5)
    print 'Terminating thread...'
    kill_thread(x)

    time.sleep(5)
    print 'Exiting'
    
          - - - - - - - - - - - - - - - - - - - - - - - - -

In DummyThread, a "self.get_ident()" appears to return the native
platform thread id (so the same as the GetCurrentThreadId() call), but
I didn't want to depend on that necessarily being the case.

Of course, while the above runs on my system, I do think it has a GIL
risk - I expect that ctypes is releasing the GIL just before calling
the native function, so there's a chance the other thread could resume
and obtain the GIL just prior to TerminateThread executing at the
Win32 layer.  My odds are probably lower in this example since the
dummy thread is sleeping most of the time.  So if I was going to use
this in practice I'd probably provide my own extension module that
wrapped TerminateThread but made sure *not* to release the GIL before
calling it.

Of course, there are other pieces of state that remained messed up,
particularly if you use the threading package as above - it still
thinks the thread is alive and would wait for it at process exit.
Setting it to a daemon works as above, but you could also get crufty
and just reach in and manually call the __stop and __delete methods of
the thread object (dealing with the name mangling).

Not sure I'd ever have the gumption to use this in practice unless my
very next step was to exit the process (in which case setting the
thread as daemon works just about as well), but it's technically
possible :-)

-- David




More information about the Python-list mailing list