linux/C++笔记-查看线程详情-pstree/pstack/gdb调试多线程
目录
- 参考资料
- 简介
- 查看主线程和新线程的关系
- 查看线程栈结构
- gdb命令目录
- 示例
- 代码
- 命令
- 1. 线程信息
- 2. 设置断点
- 3. 单步调试
- 4. 打印上下文代码
- 5. 变量打印
- 6. 观察变量
- 常见问题
参考资料
线程的查看以及利用gdb调试多线程 https://blog.csdn.net/zhangye3017/article/details/80382496
GDB教程 http://c.biancheng.net/view/8232.html
next step : https://blog.csdn.net/www_dong/article/details/117374370
简介
本文给出了常用的gdb命令解释,以及使用示例
查看主线程和新线程的关系
pstree -p 主线程id
查看线程栈结构
pstack pid
gdb命令目录
| 命令 | 用法 | 示例 |
|---|---|---|
| info threads | 显示当前可调试的所有线程,每个线程会有一个GDB为其分配的ID,操作线程时可使用此ID。 前面有*的是当前调试的线程 |
|
| thread ID(1,2,3…) | 切换当前调试的线程为指定ID的线程 | |
| break thread_test.c:123 thread all | 普通断点: 在所有线程中相应的行上设置断点 | 1. break pthread_run1 在进入pthread_run1函数时停住 2. break 20 在第20行停住 3. break +/-offset 在当前行号的前/后的offset行停住 4. break filename:linenum 在源文件filename的linenum行处停住。 |
| l | list的简写, 查看当前调试的代码上下文, 显示当前context的代码 | |
| i b | info breakpoint 的简写查看断点(包括编号) | |
| delete | 删除所有断点 delete [breakpoints num] [range...] | delete 1 或 delete 1-10 |
| d 1 | 删除指定编号的断点, 这里与delete 1 功能相同,指删除编号1的断点 | |
| n | next的简写, 单步调试, 不过当遇到包含调用函数的语句时,无论函数内部包含多少行代码,next 指令都会一步执行完 | 例: next 1 单步执行1行代码 |
| s | step的简写, 单步调试,和next的区别: 当 step 命令所执行的代码行中包含函数时,会进入该函数内部,并在函数第一行代码处停止执行 | |
| pring val_1 | 打印val_1的值 | |
| pring val_1=10 | 修改val_1的值 | |
| display val_1 | 与print类似,display 用于调试阶段查看某个变量或表达式的值 区别: 使用 display 命令查看变量或表达式的值,每当程序暂停执行(例如单步执行)时,GDB 调试器都会自动打印 而 print只打印一次 |
|
| watch val_1 | 观察val_1的值,当有变化时,停止 | |
| clear | 删除所在行的断点 | 删除函数的所有断点: clear list_insert 删除文件:函数的所有断点: clear list.c:list_delet 删除行号的所有断点: clear 12 删除文件:行号的所有断点: clear list.c:12 |
| thread apply ID1 ID2 command | 让一个或者多个线程执行GDB命令command | thread apply 2 n 表示让线程2继续执行 |
| thread apply all command | 让所有被调试线程执行GDB命令command | |
| set scheduler-locking 选项 command | 设置线程是以什么方式来执行命令 | |
| set scheduler-locking off | 不锁定任何线程,也就是所有线程都执行,这是默认值 | |
| set scheduler-locking on | 只有当前被调试程序会执行 | |
| set scheduler-locking on step | 在单步的时候,除了next过一个函数的情况 (熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为)以外, 只有当前线程会执行 |
示例
代码
#include
#include
#include
#include
#include
void my_print1(int i) {
printf("Thread1,ID: %d, value:%d\n",pthread_self(), i);
}
void my_print2(int i) {
printf("Thread2,ID: %d, value:%d\n",pthread_self(), i);
}
void thread_run1() {
int i = 0;
while (1) {
my_print1(i);
i++;
sleep(1);
}
}
void thread_run2() {
int i = 0;
while (1) {
my_print2(i);
i++;
sleep(1);
}
}
int main() {
std::thread t1(thread_run1);
std::thread t2(thread_run1);
printf("main thread\n");
t1.join();
t2.join();
return 0;
}
编译
g++ -g test_thread_gdb.cpp -o test -pthread
命令
ps -aux | grep test
gdb attach pid // pid为你的test的进程id
1. 线程信息
info thread // 查看全部线程
thread 2 // 切换到线程2
bt //
2. 设置断点
b thread_run1 // thread_run1设置断点
i b // 查看当前断点 包括编号
3. 单步调试
n 1
n
next // 以上可用于持续的单步调试
print i // 打印变量 i 的值
4. 打印上下文代码
l
list // 查看代码上下文
5. 变量打印
display i // 之后每次单步调试都会显示i的变量值
6. 观察变量
watch i // 观察i的值,当有变化时,停止
常见问题
问题1: No symbol table is loaded. Use the "file" command
使用list命令时,报以上错误
编译时加上 -g参数
g++编译
g++ -g test.cpp -o test
bazel编译
bazel build ... --compilation_mode=dbg