linux GDB 调试多线程

本文介绍使用GDB进行多线程程序调试的方法,包括自动通知新线程、线程间切换、查询现存线程、向线程发送命令及设置线程相关断点等功能。

 线程有自己的寄存器,运行时堆栈或许还会有私有内存。  
gdb提供了以下供调试多线程的进程的功能:  
*   自动通告新线程。  
*   / "thread   THREADNO/ ",一个用来在线程之间切换的命令。  
*   / "info   threads/ ",一个用来查询现存线程的命令。  
*   / "thread   apply   [THREADNO]   [ALL]   ARGS/ ",一个用来向线程提供命令的命令。  
*   线程有关的断点设置。  
注意:这些特性不是在所有gdb版本都能使用,归根结底要看操作系统是否支持。  
如果你的gdb不支持这些命令,会显示出错信息:  
(gdb)   info   threads  
(gdb)   thread   1  
Thread   ID   1   not   known.   Use   the   / "info   threads/ "   command   to  
see   the   IDs   of   currently   known   threads.  
gdb的线程级调试功能允许你观察你程序运行中所有的线程,但无论什么时候  
gdb控制,总有一个“当前”线程。调试命令对“当前”进程起作用。  
一旦gdb发现了你程序中的一个新的线程,它会自动显示有关此线程的系统信  
息。比如:  
[New   process   35   thread   27]  
不过格式和操作系统有关。  
为了调试的目的,gdb自己设置线程号。  
`info   threads/ "  
显示进程中所有的线程的概要信息。gdb按顺序显示:  
1.线程号(gdb设置)  
2.目标系统的线程标识。  
3.此线程的当前堆栈。  
一前面打/ "*/ "的线程表示是当前线程。  
例如:  
(gdb)   info   threads  
3   process   35   thread   27   0x34e5   in   sigpause   ()  
2   process   35   thread   23   0x34e5   in   sigpause   ()  
*   1   process   35   thread   13   main   (argc=1,   argv=0x7ffffff8)  
at   threadtest.c:68  
`thread   THREADNO/ "  
把线程号为THREADNO的线程设为当前线程。命令行参数THREADNO是gdb内定的  
线程号。你可以用/ "info   threads/ "命令来查看gdb内设置的线程号。gdb显示该线程  
的系统定义的标识号和线程对应的堆栈。比如:  

(gdb)   thread   2  
[Switching   to   process   35   thread   23]  
0x34e5   in   sigpause   ()  
/ "Switching后的内容取决于你的操作系统对线程标识的定义。  

`thread   apply   [THREADNO]   [ALL]   ARGS/ "  
此命令让你对一个以上的线程发出相同的命令/ "ARGS/ ",[THREADNO]的含义同上。  
如果你要向你进程中的所有的线程发出命令使用[ALL]选项。  
无论gdb何时中断了你的程序(因为一个断点或是一个信号),它自动选择信号或  
断点发生的线程为当前线程。gdb将用一个格式为/ "[Switching   to   SYSTAG]/ "的消息  
来向你报告。  

### 使用 GDB 调试多线程程序的具体指令和技巧 #### 编译准备 为了能够有效地使用 GDB 调试多线程程序,编译时需添加 `-g` 参数以包含调试信息,并禁用优化选项(如 `-O0`),从而确保生成的可执行文件保留完整的符号表信息。例如,在 C++ 中可以通过以下命令完成编译: ```bash g++ -g -O0 -pthread main.cpp -o app ``` #### 启动 GDB 并加载目标程序 启动 GDB 的方式如下所示,其中 `app` 是待调试的目标程序名称: ```bash gdb ./app ``` 随后可通过 `run` 命令启动程序。 #### 查看所有线程的状态 在 GDB 中,可以利用 `info threads` 命令获取当前进程中所有线程的相关信息[^5]。此命令会返回每一线程的 ID、目标标识以及对应的函数调用位置等内容。例如: ``` (gdb) info threads Id Target Id Frame * 1 Thread 0x7f... (LWP 1234) "app" 0x000055... in main () 2 Thread 0x7f... (LWP 1235) "app" __lll_lock_wait () at ../nptl/sysdeps/.../lowlevellock.h:135 3 Thread 0x7f... (LWP 1236) "app" epoll_wait (epfd=4, events=0x7f..., maxevents=64, timeout=-1) at ../sysdeps/unix/sysv/linux/epoll_wait.c:30 ``` #### 切换至指定线程 如果需要专注于某一特定线程的操作,则可以借助 `thread <ID>` 命令实现切换,其中 `<ID>` 表示目标线程编号[^3]。例如,要切换到第 2 号线程,输入: ``` (gdb) thread 2 ``` #### 设置针对某一线程的断点 除了常规断点外,还可以设定仅适用于某个具体线程的条件断点。语法形式为 `break <line> thread <tid>` 或更复杂的表达式 `break <line> thread <tid> if condition`。下面展示两个实例: - 当线程 2 达到源码中的第 10 行时暂停: ``` (gdb) break 10 thread 2 ``` - 若线程 2 在相同行号处满足变量 x 和 y 相等这一前提才中断: ``` (gdb) break 10 thread 2 if x == y ``` #### 获取单个或全部线程的回溯信息 对于单一选定线程而言,执行 `bt` 即能显示其堆栈跟踪详情;而对于整个应用内的所有活动线程来说,采用 `thread apply all bt` 将一次性呈现它们各自的调用链路图景^。 ``` (gdb) thread apply all bt ``` #### 定位死锁问题 面对潜在的多线程死锁状况,有多种策略可供选择。一种常见做法是在发生阻塞期间强制生成 core dump 文件后再加以剖析,这通常涉及向进程发送 SIGSEGV 信号 (`kill -11`) 来触发异常终止行为[^4]。另一种途径则是依赖详尽的日志记录机制辅助诊断流程走向。当然也可以尝试运用前面提到的各种交互手段逐步探索根本原因所在之处。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值