Python多线程出现_wait_for_tstate_lock锁错误,程序阻塞求助
解决端口扫描程序的阻塞与锁错误问题
我帮你排查了代码里的几个核心问题,这正是导致程序阻塞和_wait_for_tstate_lock错误的根源,下面是问题分析和修复方案:
问题分析
1. Queue类的可变默认参数陷阱
Python中如果用可变对象(比如[])作为函数默认参数,这个对象会被所有实例共享,也就是说你创建的所有Queue实例都会共用同一个列表,这会导致队列状态混乱,甚至引发数据不一致或隐性死锁。
2. Socket连接未设置超时
check_port方法里的socket.connect()没有设置超时时间,当目标主机对某个端口无响应时,connect会无限阻塞,直接导致线程卡住,整个程序也跟着停滞,直到你手动中断。
3. 线程循环逻辑不健壮
原check_multi_port方法用初始队列长度计算循环次数,但队列长度是动态变化的,而且当队列为空时,self.qinit.pop()会抛出IndexError,没有做异常处理,进一步加剧了程序的不稳定。
修复后的完整代码
import threading import socket class Queue(object): def __init__(self, queue=None): # 修复可变默认参数问题:用None替代[]作为默认值 self.lock = threading.Lock() self.queue = queue if queue is not None else [] self.len = len(self.queue) def append(self, value): self.lock.acquire() try: self.queue.append(value) self.len += 1 finally: self.lock.release() def pop(self): self.lock.acquire() value = None try: value = self.queue.pop() self.len -= 1 finally: self.lock.release() return value def getall(self): return self.queue class PortScanner(object): def __init__(self, host): self.qinit = Queue([20,21,22,23,24,25]) self.qport = Queue([]) self.host = host def check_port(self): s = socket.socket() # 设置2秒连接超时,避免无限阻塞 s.settimeout(2) try: port = self.qinit.pop() s.connect((self.host, port)) self.qport.append(port) print(f"Port {port} is open") except IndexError: # 队列为空时直接退出 return except Exception: # 捕获连接失败的各种异常 pass finally: # 确保socket始终被关闭 s.close() def check_multi_port(self, num_threads=2): threads = [] # 循环直到任务队列空为止 while self.qinit.len > 0: # 每次启动不超过设定线程数的任务,同时避免队列空时创建线程 current_threads = min(num_threads, self.qinit.len) for _ in range(current_threads): t = threading.Thread(target=self.check_port) threads.append(t) t.start() # 等待当前批次的线程全部完成 for t in threads: t.join() threads = [] return self.qport.getall() # 测试示例 if __name__ == "__main__": scanner = PortScanner("127.0.0.1") open_ports = scanner.check_multi_port(num_threads=2) print("Open ports:", open_ports)
关键修复点说明
- 可变默认参数修复:将
queue=[]改为queue=None,并在内部初始化空列表,确保每个Queue实例拥有独立的队列。 - Socket超时设置:通过
settimeout(2)给连接设置2秒超时,确保线程不会因无响应的端口无限阻塞。 - 循环逻辑优化:改为动态判断队列长度,直到队列为空才停止,同时处理队列为空时的
pop异常,让线程能正常退出。
这样修改后,程序不会再出现阻塞,_wait_for_tstate_lock的错误也会消失——因为线程不再卡在无限阻塞的状态,能正常结束,主线程的join操作也能顺利完成。
内容的提问来源于stack exchange,提问作者luke
相关产品推荐
相关产品推荐

