I re-factored some code today, and in the process managed to create a lock deadlock for myself. In the end it turned out to be an exception was being thrown when a lock was held, and adding a try / finally resolved the real underlying problem. However, in the process I ended up writing this little helper that I am sure will be useful in the future.
import gflags
import thread
import threading
import traceback
import logging
...
FLAGS = gflags.FLAGS
gflags.DEFINE_boolean('dumplocks', False,
'If true, dumps information about lock activity')
...
class LockHelper(object):
"""A wrapper which makes it easier to see what locks are doing."""
lock = thread.allocate_lock()
def acquire(self):
if FLAGS.dumplocks:
logging.info('%s acquiring lock' % threading.currentThread().getName())
for s in traceback.extract_stack():
logging.info(' Trace %s:%s [%s] %s' % s)
self.lock.acquire()
def release(self):
if FLAGS.dumplocks:
logging.info('%s releasing lock' % threading.currentThread().getName())
for s in traceback.extract_stack():
logging.info(' Trace %s:%s [%s] %s' % s)
self.lock.release()
Now I can just use this helper in the place of thread.allocate_lock() when I want to see what is happening with locking. It saved me a lot of staring at random code today.