Threading problems at program exit
Ype Kingma
ykingma at accessforall.nl
Sat Nov 30 05:23:24 EST 2002
Dave Cole wrote:
> The following program demonstrates a problem I am experiencing with
> the threading module. I have an object (A) which holds a lock on
> another object (B). When object A is deleted I want it to release any
> lock it may still be holding on object B.
>
> Everything works fine except when the program terminates.
>
> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> import sys
> import threading
>
> class Locked:
> def __init__(self, lock):
> self._lock = lock
> self._lock_count = 0
> self._thread = None
> self._log = sys.stderr.write
> self._current_thread = threading.currentThread
> self.lock()
>
> def lock(self):
> self._log('locked in %s\n' % self._current_thread())
> self._lock.acquire()
> self._lock_count += 1
>
> def unlock(self):
> self._log('unlocked in %s\n' % self._current_thread())
> self._lock_count -= 1
> self._lock.release()
>
> def __del__(self):
> while self._lock_count:
> self.unlock()
>
> obj = Locked(threading.RLock())
> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
>
> When I run this program I get the following:
>
> locked in <_MainThread(MainThread, started)>
> unlocked in <_DummyThread(Dummy-1, started daemon)>
> Exception exceptions.AssertionError: <exceptions.AssertionError instance
> at 0x814fbfc> in <bound method Locked.__del__ of <__main__.Locked instance
> at 0x816e5f4>> ignored
>
> It looks like interpreter is deleting thread objects before objects
> which hold locks in those threads. Is there any kosher way I can
> avoid the problem?
>
> The only way I can think to fix it is a bit non-kosher:
>
> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> import sys
> import threading
>
> class Locked:
> def __init__(self, lock):
> self._lock = lock
> self._lock_count = 0
> self._thread = None
> self._log = sys.stderr.write
> self._current_thread = threading.currentThread
> self.lock()
>
> def lock(self):
> self._log('locked in %s\n' % self._current_thread())
> self._lock.acquire()
> self._lock_count += 1
>
> def unlock(self):
> self._log('unlocked in %s\n' % self._current_thread())
> self._lock_count -= 1
> self._lock.release()
>
> def __del__(self):
> if self._lock_count:
> count, owner = self._lock._release_save()
> self._log('owner was %s\n' % owner)
> owner = self._current_thread()
> self._log('owner is now %s\n' % owner)
> self._lock._acquire_restore((count, owner))
> while self._lock_count:
> self.unlock()
>
> obj = Locked(threading.RLock())
> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
>
> This prints the following:
>
> locked in <_MainThread(MainThread, started)>
> owner was <_MainThread(MainThread, stopped)>
> owner is now <_DummyThread(Dummy-1, started daemon)>
> unlocked in <_DummyThread(Dummy-1, started daemon)>
>
> The trouble is that it requires the use of private methods of the
> RLock class.
>
> Is there a better or more kosher way?
>
> - Dave
You might consider not using the __del__ method at all because
'it is not guaranteed that __del__() methods are called for objects that
still exist when the interpreter exits. ' (quoted from the language ref).
Then use:
obj = Locked(threading.RLock())
try:
# whatever needs to be done with obj
finally:
obj.unlock()
Regards,
Ype
--
email at xs4all.nl
More information about the Python-list
mailing list