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 1delete 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