strace 不能直接判断锁是否被占用,但能通过挂起的 futex(futex_wait_private) 调用暴露线程阻塞在互斥锁上;需逐个 attach 线程(strace -p )观察相同地址的 futex 等待,结合代码中打印的 mutex 地址比对确认。

strace 不能直接告诉你“锁是否被占用”,但能清晰暴露线程卡在 futex 上——这就是互斥锁阻塞最典型的现场。
怎么用 strace 看出哪个线程在等锁
当线程因获取 pthread_mutex_t 失败而阻塞时,glibc 会调用内核的 futex 系统调用进入等待。strace 能捕获这一行为,且输出中会明确显示该调用未返回(即卡住)。
- 先用
ps -T -p <pid></pid>或top -H -p <pid></pid>列出所有线程及其 LWP ID(轻量级进程 ID,即线程 ID) - 对每个可疑线程执行:
sudo strace -p <lwp_id></lwp_id> - 如果线程正阻塞在锁上,你会看到类似这样的挂起输出:
futex(0x7f8b4c0012a0, FUTEX_WAIT_PRIVATE, 2, NULL—— 注意末尾没有) = ?或返回值,表示调用尚未完成 - 对比多个线程的 strace 输出:
futex地址相同(如0x7f8b4c0012a0)意味着它们在争抢同一个锁
为什么用 -f 参数反而可能错过关键线索
strace -f -p <pid></pid> 会跟踪主线程及其所有子线程,但输出混杂、难以定位具体是哪个线程卡在哪条 futex 上。尤其在线程数多、系统调用频繁时,关键阻塞信息容易被淹没。
Linux系统管理专家,覆盖12大模块:用户权限、SSH、存储、网络、systemd、防火墙、日志监控、备份恢复、TLS证书、Ansible、容器、IaC。提供配置、验证、加固、监控、备份、自动化、故障排查、回滚闭环。关键词:useradd、sudo、sshd_config、chmod、SEL...
- 真实排查中,应优先逐个 attach 线程(
strace -p <lwp_id></lwp_id>),而非依赖-f -
-f更适合观察“锁争抢全过程”:比如一个线程刚释放锁(futex(...FUTEX_WAKE...)),另一个立刻进入FUTEX_WAIT - 若必须用
-f,务必配合-o trace.log输出到文件,并用grep "futex.*WAIT"过滤
如何把 strace 中的 futex 地址对应到代码里的 mutex 变量
futex 第一个参数是用户态锁变量的地址,但这个地址是虚拟内存地址,需在程序中打印出来才能比对。
- 在初始化互斥锁后,加一句日志:
printf("g_mutex addr: %p\n", (void*)&g_mutex); - 确保该日志在程序启动早期执行(避免被优化掉或延迟打印)
- 运行程序,记录下打印出的地址(如
0x7f8b4c0012a0),再与 strace 中的futex地址比对 - 注意:ASLR 可能导致每次地址不同,调试时可临时关闭:
setarch $(uname -m) -R ./your_program
常见误判和干扰项
不是所有 futex 都代表互斥锁问题;很多同步原语(如 pthread_cond_wait、sem_wait)底层也走 futex,需结合上下文判断。
- 看第二个参数:
FUTEX_WAIT/FUTEX_WAIT_PRIVATE通常是锁或条件变量阻塞;FUTEX_WAKE是唤醒 - 看调用位置:如果 strace 显示线程刚执行完
pthread_mutex_lock就卡在futex,基本可断定是锁竞争或死锁 - 警惕
nanosleep、poll、epoll_wait等非锁类阻塞调用,它们不会导致“多个线程等同一地址” - 递归加锁未定义行为:快速锁(
PTHREAD_MUTEX_FAST_NP)遇到同一线程重复加锁会直接死锁,且 strace 表现与正常争锁完全一致
真正难的不是看到 futex,而是确认那个地址对应的锁变量在代码里是否被正确初始化、是否遗漏解锁、是否跨函数/线程以不一致顺序加锁——strace 给你的是证据链起点,不是结论。










