linux gdb-多线程调试

简介: linux下应用程序的调试工具主要就是gdb,可能你已经习惯了IDE形式的调试工具。也许刚开始使用gdb作为调试工具,会有诸多的不变,但是一旦你学会了如何使用gdb你就会被其富有魔力的功能所吸引的,下面开始逐步的学习linux下gdb的使用方式。

linux下应用程序的调试工具主要就是gdb,可能你已经习惯了IDE形式的调试工具。也许刚开始使用gdb作为调试工具,会有诸多的不变,但是一旦你学会了如何使用gdb你就会被其富有魔力的功能所吸引的,下面开始逐步的学习linux下gdb的使用方式。


一直以来对于gdb在多线程调试方面的应用好奇,最近,由于项目需要,学习了linux下的gdb在多线程下的调试方法。下面就结合一个简单的案例介绍一下gdb的多线程调试方法。其中,本例子还介绍了如何调试链接有静态库的多线程应用程序。


1.理论介绍


gdb支持的用于多线程调试的工具如下:


能够自动的提醒新线程的创建。


  • ‘thred threadno’,实现在不同线程间切换。


  • ‘info thead’,可以查看存在的线程信息。


  • ‘thread applay [threadno] [all] args’  ,在指定的线程上执行特定的命令args。

可以在线程中设置特定的断点。


  • ‘set print thread-events’,用于设定是否提示线程启动或停止时的信息。


  • ‘set libthread-db-search-path path’,用于是用户可以自己制定libthread-db 的路径信息。


  • 'set scheduler-locking mode',在某些操作系统中,你可以通过锁住OS的调度行为,这样可以就可以改变GDB默认的行为,达到同一时间只有一个线程在运行的目的。


  • off:没有锁定,所有线程可以在任何时间运行。


  • on:锁定线程,只有当前线程在运行。


  • step:该模式是对single-stepping模式的优化。此模式会阻止其他线程在当前线程单步调试时,抢占当前线。因此调试的焦点不会被以外的改变。其他线程不可能抢占当前的调试线程。其他线程只有下列情况下会重新获得运行的机会:


当你‘next’一个函数调用的时候。


当你使用诸如‘continue’、‘until‘、’finish‘命令的时候。


其他线程遇到设置好的断点的时候。


1.1线程创建提醒


当应用程序创建线程的时候,如果你设置了’set print thread-events‘,那么他会自动提示新创建线程的信息,GNU/linux 下的提示信息如下:


[New Thread 0x41e02940 (LWP 25582)]


1.2显示线程信息


info thread用于显示系统中正在运行的所有线程的信息。信息主要包括如下几项:

GDB分配的id号。


目标系统定义的线程id(systag)。


线程的名字,如果存在的话,会被显示出来。用户可以自定义线程的名字,或者由程序自己指定。


线程相关的栈的信息。


其中,*表示当前正在运行的线程,下面是一个多线程的相关信息。


(gdb) info threads
Id Target Id Frame
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


1.3切换线程


thread threadno用于在同步线程之间实现切换。threadno即上面显示的GDB自定义的线程的id号。线程切换成功后,会打印该线程的相关信息,比如栈信息。


(gdb) thread 2 [Switching to thread 2 (Thread 0xb7fdab70 (LWP 12747))] #0 some_function (ignore=0x0) at example.c:8 8 printf ("hello\n");


变量$_thread 记录了当前线程的id号。你或许在设置断点条件或脚本的时候会用到该变量。


1.4执行命令


thread apply[threadid|all] command,该工具用于在一个或多个线程执行指定的命令command。threadid可以是一个或多个线程id,或是一个范围值,例如,1-3


1.5定义/find线程名


thread name,可以通过该工具实现线程名的重新定义。一般,系统会为每一个线程定义一个名字,例如GNU/linux,使用该命令后会将系统定义的线程名称覆盖掉。


thread find [regexp],其中regexp可以是线程的systag,例如,LWP 25582中的25582,或线程名(系统定义的或用户自定义的)


2.实例调试


下面通过一个实例,具体演示一下gdb  thread调试。


2.1静态库编译


下面为一个简单的函数用于打印不同的字符串。


#include<iostream>                                                                                                                    
#include<string>
#include"print.h"
using namespace std;
void print(string words)
{
        std::cout << words << std::endl;
}


将其编译成静态库


g++ -c print.cpp 
ar crs libprint.a print.o


2.2 链接静态库


下面为一个多线程程序的打印程序,很简单


#include<iostream>
#include<pthread.h>
#include"print.h"
void* threadPrintHello(void* arg)
{
  while(1)
  {
    sleep(5);
    print(string("Hello"));
  }
}
void* threadPrintWorld(void* arg)
{
  while(1)
  {
    sleep(5);
    print(string("World"));
  }
}
int main( int argc , char* argv[])
{
  pthread_t pid_hello , pid_world;
  int ret = 0;
  ret = pthread_create(&pid_hello , NULL , threadPrintHello , NULL);
  if( ret != 0 )
  {
    std::cout << "Create threadHello error" << std::endl;
    return -1;
  }
  ret = pthread_create(&pid_world , NULL , threadPrintWorld , NULL);
  if( ret != 0 )
  {
    std::cout << "Create threadWorld error" << std::endl;
    return -1;
  }
  while(1)
  {
    sleep(10);
    std::cout << "In main thread"  << std::endl;
  } 
  pthread_join(pid_hello , NULL);
  pthread_join(pid_world , NULL);
  return 0;
}


编译程序


g++ -o thread thread.cpp -lpthread -lprint


2.3调试程序


启动程序


$./thread 
进程id
$ps aux |grep thred
1000     24931  0.0  0.0  21892   912 pts/0    tl+  03:04   0:00 src/thread
attach该进程
$sudo gdb thread 24931


显示线程信息


(gdb) info thread
  Id   Target Id         Frame 
* 3    Thread 0xb7471b40 (LWP 24932) "threadPrintHello" threadPrintHello (arg=0x0) at thread.cpp:10
  2    Thread 0xb6c70b40 (LWP 24933) "thread" 0xb7779424 in __kernel_vsyscall ()
  1    Thread 0xb7473700 (LWP 24931) "thread" 0xb7779424 in __kernel_vsyscall ()


相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
7天前
|
缓存 NoSQL Linux
Linux调试
本文介绍了Linux调试、性能分析和追踪的培训资料,涵盖调试、性能分析和追踪的基础知识及常用工具。
148 6
Linux调试
|
3月前
|
NoSQL Linux C语言
Linux GDB 调试
Linux GDB 调试
62 10
|
3月前
|
NoSQL Linux C语言
嵌入式GDB调试Linux C程序或交叉编译(开发板)
【8月更文挑战第24天】本文档介绍了如何在嵌入式环境下使用GDB调试Linux C程序及进行交叉编译。调试步骤包括:编译程序时加入`-g`选项以生成调试信息;启动GDB并加载程序;设置断点;运行程序至断点;单步执行代码;查看变量值;继续执行或退出GDB。对于交叉编译,需安装对应架构的交叉编译工具链,配置编译环境,使用工具链编译程序,并将程序传输到开发板进行调试。过程中可能遇到工具链不匹配等问题,需针对性解决。
|
3月前
|
Ubuntu Linux
内核实验(四):Qemu调试Linux内核,实现NFS挂载
本文介绍了在Qemu虚拟机中配置NFS挂载的过程,包括服务端的NFS服务器安装、配置和启动,客户端的DHCP脚本添加和开机脚本修改,以及在Qemu中挂载NFS、测试连通性和解决挂载失败的方法。
186 0
内核实验(四):Qemu调试Linux内核,实现NFS挂载
|
3月前
|
NoSQL Linux 编译器
内核实验(一):使用QEMU+GDB断点调试Linux内核代码
如何配置环境并使用QEMU虚拟机结合GDB进行Linux内核代码的断点调试,包括安装QEMU、交叉编译工具链,编译内核以及通过GDB远程连接进行调试的详细步骤。
135 0
内核实验(一):使用QEMU+GDB断点调试Linux内核代码
|
程序员 编译器 Linux
linux gdb-多线程调试
相信使用C/C++语言开发软件的程序猿们都经历过‘栈溢出’的问题。‘栈溢出’问题通常十分的隐蔽,有的时候问题复现也十分的困难。每当软件出现莫名其妙的问题时,总是有人怀疑是不是栈溢出了,但是问题的排查又十分的困难,所以,‘栈溢出’就是广大C/C++开发者的噩梦。
151 0
|
3天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
18 3
|
3天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
16 2
|
11天前
|
缓存 监控 Linux
|
14天前
|
Linux Shell 数据安全/隐私保护