You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:40:32