gdb attach上游进程排查死锁需先确认进程状态(非d态)和权限(同用户/root或yama.ptrace_scope=0),再用info threads和thread apply all bt -n 15定位停在pthread_mutex_lock等锁函数的线程,人工比对锁地址交叉等待关系。

直接用 gdb attach 到卡住的 upstream 进程,重点看哪些线程停在锁函数上、锁地址是否重复、谁持有哪把锁又在等哪把锁——死锁本质是循环等待,不是单点卡住。
确认进程状态和权限是否允许 attach
上游服务锁死时,先别急着 gdb。执行:
ps -o pid,stat,comm -p $(pgrep -f "upstream.*process")
若状态为 D(uninterruptible sleep),说明卡在内核态,gdb 无法 attach,得换 /proc/pid/stack 或用 gcore 抓快照离线分析。
若为 T 或 R/S,再检查权限:必须是同一用户或 root;非 root 用户需确保 /proc/sys/kernel/yama/ptrace_scope = 0,或改用 sudo gdb -p PID。
attach 后快速定位可疑线程
进入 gdb 后立即执行:
info threads —— 找出状态异常的线程(比如大量显示 sleep 或 running 但栈顶是锁函数)
thread apply all bt -n 15 —— 限制栈深度,避免模板展开刷屏
重点关注调用链中含以下关键词的线程:
• pthread_mutex_lock
• __lll_lock_wait
• std::mutex::lock 或 absl::Mutex::Lock
• futex(FUTEX_WAIT_PRIVATE)(strace -p PID 可辅助验证)
人工比对锁依赖关系
死锁至少涉及两个线程、两把锁、交叉等待。逐个检查疑似线程:
• 切到该线程:thread
• 查看当前帧:frame 2(通常第 2–4 层是实际加锁位置)
• 打印锁变量(如 m1、mutex_abc):p m1(部分 std::mutex 支持有限,但能看地址)
• 记录每条线索:
– 线程 A:持有锁 0x7f…a0,等待锁 0x7f…b0
– 线程 B:持有锁 0x7f…b0,等待锁 0x7f…a0
只要这两条同时存在,就是典型 AB-BA 死锁。
补充技巧:避免干扰线上服务
gdb attach 是只读调试,不影响进程运行,但操作要快:
• 不要 run 或 continue,除非你明确要复现
• 查完立刻 detach:detach + quit
• 若进程响应极慢,优先用 pstack PID 快速抓一次快照(轻量,不阻塞)
• 生产环境建议提前编译带 -g -O2(保留符号+适度优化),否则 gdb 里变量显示











