17.2.5.2 调试
找出死锁可能是处理线程最困难的方面之一。sys._current_frames()会有所帮助,它能准确地显示出线程在哪里停止。
import sys
import threading
import time
io_lock = threading.Lock()
blocker = threading.Lock()
def block(i):
t = threading.current_thread()
with io_lock:
print('{} with ident {} going to sleep'.format(
t.name,t.ident))
if i:
blocker.acquire() # Acquired but never released
time.sleep(0.2)
with io_lock:
print(t.name,'finishing')
return
# Create and start several threads that "block."
threads = [
threading.Thread(target=block,args=(i,))
for i in range(3)
]
for t in threads:
t.setDaemon(True)
t.start()
# Map the threads from their identifier to the thread object.
threads_by_ident = dict((t.ident,t) for t in threads)
# Show where each thread is "blocked."
time.sleep(0.01)
with io_lock:
for ident,frame in sys._current_frames().items():
t = threads_by_ident.get(ident)
if not t:
# Main thread
continue
print('{} stopped in {} at line {} of {}'.format(
t.name,frame.f_code.co_name,
frame.f_lineno,frame.f_code.co_filename))
sys._current_frames()返回的字典以线程标识符为键,而不是线程名。需要稍做一点工作将这些标识符映射为线程对象。
由于线程-1没有休眠,在检查它的状态之前他就已经完成了。由于这个线程不再是活动的,所以不会出现在输出中。线程-2请求锁阻塞器(blocker),然后休眠很短一段时间。与此同时,线程-3尝试请求阻塞器,不过无法得到,因为已经被线程-2占用。