[Python-bugs-list] Bug with Threaded exceptions? (PR#151)
jam@camros.com
jam@camros.com
Tue, 7 Dec 1999 00:13:55 -0500 (EST)
Full_Name: Jeffrey A. Marshall
Version: 1.5.2
OS: solaris 2.6, linux (rh 6.0)
Submission from: phantasm.paragon-software.com (204.91.29.130)
We've run into a possible bug when using exceptions within a threaded
python program. It seems as though objects on the python execution stack
are "garbage" collected in a different thread than where the were created.
This isn't a real problem, except we're trying to make our developer's life
easier by defining classes which have certain (thread-related) semantics
associated with their (instance's) life-times.
Maybe this problem only shows up due to the fact that we're not catching an
exception within our top-level thread function.
I've included a script demonstrating the problem below, along with the
workaround we're currently using:
thanks,
-jeff
----- python code follows -------------
import threading
# this is the class we've developed to help with
# making sure that a given mutex (lock) gets
# released, even when exceptions are raised
#
# The intent is that creating an instance of "BlockLock"
# acquires the given lock object
#
# And that when the BlockLock goes out of scope (or
# gets deleted) it automagically releases the lock
#
class BlockLock:
def __init__ (self, lock):
self.__lock = lock
self.__thread = threading.currentThread ()
lock.acquire ()
print "%s.__init__: self=%s thread=%s" % (self.__class__.__name__,
self,
threading.currentThread ())
def __del__ (self):
thr = threading.currentThread ()
if thr is not self.__thread:
print "WARNING: releasing lock in diff. thread (%s)" % (self.__thread,)
print "%s.__del__: self=%s thread=%s" % (self.__class__.__name__,
self,
thr)
self.__lock.release ()
the_lock = threading.Lock ()
def my_buggy_thread_fun ():
# buggy function, showing that the __del__ method in block lock
# is
a = BlockLock (the_lock)
assert 0
def my_fixed_thread_fun ():
# Same as above, our workaround is to always place
# a `try'/`finally' block around all the code... Doing
# this almost defeats the whole purpose of having
# the BlockLock class...
a = BlockLock (the_lock)
try:
assert 0
finally:
del a
def show_bug ():
thr = threading.Thread (target=my_buggy_thread_fun)
print "starting bad thread: ", `thr`
thr.start ()
thr.join ()
print "bad thread exited"
thr = threading.Thread (target=my_fixed_thread_fun)
print "starting fixed thread: ", `thr`
thr.start ()
thr.join ()
print "fixed thread exited"
if __name__ == '__main__':
show_bug ()