watch命令仅在变量被写入时触发,rwatch监视读操作,awatch监控读写但开销大易误触;多线程下必须用thread限定目标线程,否则可能错过关键修改。

watch 命令只监控写入,不是“读写都停”
很多人误以为 watch 会响应读或写操作,其实它只在变量**被修改(写入)时触发中断**。这是最常用也最安全的监视方式,适合定位“谁偷偷改了这个值”。比如你发现全局计数器 g_counter 在某次调用后变成负数,但找不到赋值点,直接 watch g_counter 就能立刻捕获写入位置。
注意:GDB 默认尝试用硬件寄存器实现该 watchpoint;若硬件资源不足(比如 x86_64 上通常最多 4 个硬件 watchpoint),它会自动降级为软件模拟,但可能漏掉某些优化后的写入(如寄存器内运算未落内存)。此时你会看到提示 Watchpoint N: g_counter (software watchpoint)。
想监视读操作?必须用 rwatch
如果问题出在“不该读的地方读了”,比如某个指针被意外解引用导致段错误,但你不确定哪行代码读了它,就得用 rwatch:
-
rwatch *ptr—— 监视指针指向的内存是否被读取(注意加*) -
rwatch array[0]—— 监视数组首元素是否被读(不加*也能工作,但语义更清晰) - 多线程下慎用:
rwatch可能因频繁读取(如调试器自己读变量)而反复中断,建议配合ignore N 10忽略前 10 次命中
awatch 是读+写全监控,但开销大且易误触
awatch 看似“省事”,实际容易干扰调试流程。比如监视一个被频繁读取的结构体字段 awatch obj->state,可能在日志打印、条件判断甚至 GDB 自身 print 时就中断,反而掩盖真正的问题点。
更危险的是:当目标地址不在可执行栈/堆上(如只读数据段),awatch 可能直接失败并报错 Cannot insert hardware watchpoint。这时要么换 watch 或 rwatch,要么手动用 watch *(int*)0xdeadbeef 绕过符号解析。
多线程下必须限定线程,否则 watchpoint 失效
默认情况下,任何线程修改目标变量都会触发 watch。但在多线程竞争场景中,你往往只想盯住某个 worker 线程——比如怀疑线程 T2 错误地覆盖了共享缓冲区 shared_buf,那就得绑定线程:
- 先用
info threads查到目标线程 ID(如Thread 0x7ffff759c700 (LWP 3566)对应 tid 3566) - 再设带线程约束的观察点:
watch shared_buf thread 3566 - 验证是否生效:
info watchpoints输出里该 watchpoint 的thread列应显示对应数字
漏掉这步,你可能在 T1 修改时中断,却完全错过 T2 的关键写入——因为 watchpoint 一旦命中就暂停所有线程,后续修改被阻塞了。
硬件 watchpoint 数量有限,表达式越简单越好;涉及指针解引用时,务必确认地址有效;多线程场景下不加 thread 修饰的 watch 很可能让你追错方向。











