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.