How to "kill" orphaned threads at program exit

G

Giampaolo Rodola'

Hi,
I know that it's not possible to "kill" threads but I'm wondering if
does exist some workaround for my problem.
I have a test suite which does a massive usage of threads.
Sometimes happens that one test fails, the test suite keeps running
until the end, and when it's finished the program hangs on and the
only way to stop is to kill it manually.
I noticed that, at the end of the program, I can call
threading.enumerate() and see the pending thread objects:

def test_main():
...
start_suite()
print threading.enumerate()

I was wondering if I can do anything with that.
I took a look at test/test_support which has threading_setup() and
threading_cleanup() functions.
Could such functions be useful to me?


Thanks in advance,


--- Giampaolo
http://code.google.com/p/pyftpdlib/
 
R

Roy Smith

"Giampaolo Rodola' said:
Hi,
I know that it's not possible to "kill" threads but I'm wondering if
does exist some workaround for my problem.
I have a test suite which does a massive usage of threads.
Sometimes happens that one test fails, the test suite keeps running
until the end, and when it's finished the program hangs on and the
only way to stop is to kill it manually.

You don't say how you're creating your threads, so I'll assume you're using
threading.Thread(). After creating each thread, and before calling start()
on it, call setDaemon(True).
 
G

Gabriel Genellina

You don't say how you're creating your threads, so I'll assume you're
using
threading.Thread(). After creating each thread, and before calling
start()
on it, call setDaemon(True).

The hard part is, then, to figure out some condition for the non-daemon
thread to wait for before exiting.
As a last resort -let's say, after waiting for N seconds for all threads
to exit- one can use PyThreadState_SetAsyncExc to "inject" an exception
into the unfinished threads. I think there is a recipe in the Python
Cookbook for doing that using ctypes.
 
G

Giampaolo Rodola'

You don't say how you're creating your threads, so I'll assume you're using
threading.Thread(). After creating each thread, and before calling start()
on it, call setDaemon(True).

Apparently it doesn't make any difference.
A curious thing is that by putting a "print 1" as last instruction the
pending threads get killed and the program exits (Windows XP sp3 32
bit).


--- Giampaolo
http://code.google.com/p/pyftpdlib/
 
B

BlueBird

Hi,
I know that it's not possible to "kill" threads but I'm wondering if
does exist some workaround for my problem.
I have a test suite which does a massive usage of threads.
Sometimes happens that one test fails, the test suite keeps running
until the end, and when it's finished the program hangs on and the
only way to stop is to kill it manually.
I noticed that, at the end of the program, I can call
threading.enumerate() and see the pending thread objects:

Hi,

The way I handle it is to make sure that after each test, the thread
count has returned to what I expect.

It is possible to kill a thread if it's not blocked on a system call.
It's highly unrecommended for standard usage but your use case exactly
the one where the ability to kill a thread is very useful.

I use the following code, which I borrowed to the Python Cook book
somewhere:

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 )



cheers,

Philippe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top