Python threading.Lock使用异常:多线程触发不符合预期的问题排查与修复
为啥你的锁没生效?问题分析+修复方案
嘿,我来帮你捋清楚为啥代码里的锁没起作用,还触发了两个线程——主要是两个小问题在搞鬼:
1. 竞态条件:检查锁的操作不是原子的
你在thread_test里先判断if not lock.locked(),再创建线程,但这两步之间没有锁保护!当主函数里连续调用t1 = thread_test(lock)和t2 = thread_test(lock)时,第一个thread_test刚检查完锁没被占用,还没等新线程启动并拿到锁,第二个thread_test就已经完成了同样的检查,也觉得锁是空的,于是也创建了线程。这就是典型的竞态条件,两个请求抢着通过了“未锁”的检查。
2. 线程参数传递写错了
创建线程时args=(lock)这个写法有坑:括号里只放单个元素时,Python不会把它当成元组,而是直接把lock当作可迭代对象传递。正确的写法应该是args=(lock,),加个逗号,这样才是传递一个包含单个元素的元组,避免参数不匹配的问题(虽然你这里没报错,但这是个不良习惯)。
修复后的完整代码
#!/usr/bin/python # -*- coding:utf-8 -*- import time import threading def within_mutex(): print "###########in mutex############" n = 0 while n<5: print "waiting ...", n n += 1 time.sleep(1) print "##########end mutex############" def check_thread(lock): print "~~~~~~~~~~~in thread~~~~~~~~~~~~" print "=====before mutex======", lock.locked() with lock: print "get mutex, trigger a new thread" print "=====in mutex======", lock.locked() within_mutex() print "=====after mutex======", lock.locked() print "~~~~~~~~~~~end thread~~~~~~~~~~~~" def thread_test(lock): # 核心修复:用锁把检查+创建线程变成原子操作 with lock: # 这里其实可以简化成直接创建线程(因为with已经拿到锁了),但保留你的逻辑习惯 if not lock.locked(): thread1 = threading.Thread(target=check_thread, args=(lock,)) thread1.start() print "End thread_test" return 11 if __name__ == '__main__': lock = threading.Lock() t1 = thread_test(lock) t2 = thread_test(lock) print "t1 = ",t1 print "t2 = ",t2
修复逻辑说明
- 原子化操作:在
thread_test里,我用with lock:把检查锁和创建线程的代码包起来。第一个thread_test调用时会先抢到锁,完成检查和线程创建后才释放;第二个thread_test过来时,锁已经被刚启动的check_thread拿走了,所以检查lock.locked()会返回True,不会创建新线程。 - 修正参数传递:把
args=(lock)改成args=(lock,),确保参数正确传递给线程函数。
现在运行代码,就能看到只有一个线程被触发,第二个thread_test直接返回11,完全符合你的预期啦~
内容的提问来源于stack exchange,提问作者zhwlx22
相关产品推荐
相关产品推荐

