Linux下用GDB调试多线程程序

本文介绍如何使用GDB调试多线程程序,包括显示所有线程、切换线程、控制多个线程执行指令等技巧,并通过具体示例演示如何使用线程锁和non-stop模式进行调试。

我们都知道GDB是Linux下面一款强大程序调试的工具,以前我们都是用GDB来调试单线程程序,今天我们来谈一谈如何用GDB来调试多线程程序把。

有关GDB的基本指令在这里就不叙述了,如果感兴趣的可以看看下面这篇博客:
http://blog.youkuaiyun.com/bit_clearoff/article/details/53966718


调试多线程的相关指令

显示所有进程

info threads

这条指令显示可以调试的所有线程,gdb会为每个线程分配一个ID,这个ID和线程ID不同,ID号一般从1开始。

切换线程指令

为什么要切换线程呢?因为gdb默认在调试多线程程序时只跟踪主线程,而新创建的线程都阻塞在线程创建函数pthread_create处。如果我们不切换,那么我们就无法调试我们在主线程中所创建的线程。

thread ID

这条指令用来切换当前调试的线程为指定的ID号的线程,ID为GDB为线程所分配的ID.


多个线程控制指令

//指定多个线程执行command指令,其中commandgdb中的指令
thread apply ID1 ID2 ...IDn command   
//指定所有线程执行command指令,其中command为gdb中的指令
thread apply all command

设置线程调试状态指令

线程锁
//线程锁
   set scheduler-locking off|on

off:不锁定任何线程,当程序继续运行的时候如果有断点,那么就把所有的线程都暂停下来,直到你指定某个线程继续执行,如果在当前线程下使用continue的话那么会启动所有线程(GDB默认);
on:打开线程锁,锁定其他线程,只有当前线程执行。

non-stop模式

为了对上面的这种一个线程中断在一个断点上,其他所有的线程都会被freeze. gdb v7.0引入了non-stop模式,在这个模式下:
1. 当某个或多个线程在一个断点上,其他线程仍会并行运行
2. 你可以选择某个被中断的线程,只让他运行。
3.
non-stop模式表示不停止模式,除了断点有关的进程会被停下来,其他线程会继续执行。
设置non-stop模式,打开gdb后,在开始r之前,首先连续输入下面的指令

set target-async 1
set pagination off
set non-stop on

相关案例

首先,我们插入多线程调试的代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>

void* PthreadRun1(void* arg)
{
    int count=5;
    while(count--){
        printf("Thread1::It's %ld pthread running...\n",pthread_self());
        sleep(1);
    }
    pthread_exit((void*)0);
}

void* PthreadRun2(void* arg)
{
    int count=5;
    while(count--){
        printf("Thread2::It's %ld pthread running...\n",pthread_self());
        sleep(1);
    }
    pthread_exit((void*)0);
}

int main()
{
    pthread_t id1,id2;

    if(0!=pthread_create(&id1,NULL,PthreadRun1,NULL))
    {
        printf("create id1 pthread error...\n");
        exit(1);
    }
    if(0!=pthread_create(&id2,NULL,PthreadRun2,NULL))
    {
        printf("create id2 pthread error...\n");
        exit(1);
    }
    pthread_join(id1,NULL);
    pthread_join(id2,NULL);
    return 0;
}

我们先来看看gdb默认对多线程的调试时怎样的:
(默认多线程)

我们发现在默认情况下,gdb只跟踪主线程,而新创建的线程都被阻塞在pthread_create函数处,如果我们运行到pthread_join函数或者主线程被终止了,此时我们在主线程中创建的线程才会被终止,否则在主线程中创建的线程会被一直阻塞。


下面,我们来使用上面提到的gdb指令来调试多线程程序,首先我们在默认模式下调试。
(多线程调试1)


下面,我们使用线程锁来调试多线程程序。
(多线程调试2)

我们发现当我们设置了线程锁后再次continue时,这次只有一个线程在运行了,而且是当前线程。


最后,我们使用多线程的non-stop模式来调试多线程程序。
(多线程调试3)

<think>嗯,用户问的是在Linux下用GDB调试多线程程序时卡在创建启动线程那里不动的问题。我需要先回忆一下可能的原因和解决方法。 首先,可能的情况是主线程创建子线程时,子线程还没开始运行或者被挂起。GDB默认可能只跟踪主线程,其他线程可能暂停了。这时候需要检查线程的状态,用`info threads`看看所有线程的情况,是否子线程处于暂停状态。 然后,用户可能没有正确处理线程同步,比如主线程创建线程后没有等待,导致子线程没机会运行。这时候需要检查代码中是否有pthread_join或者适当的同步机制。 还有可能是断点设置的位置有问题。比如在子线程入口函数处设置了断点,但线程还没执行到那里,而主线程又在等待,导致死锁。这时候需要确认断点的位置,或者使用`set scheduler-locking off`让所有线程同时运行。 另外,GDB的调度策略设置也可能影响。默认是`set scheduler-locking off`,允许线程自由运行。如果设置成了`step`或者`on`,可能导致其他线程被锁定,无法创建。这时候需要调整设置。 还有可能是在动态链接库加载时卡住,特别是在使用pthread库的情况下。可以尝试在程序启动后设置断点,而不是在启动时。 还有信号处理的问题,比如子线程收到某个信号被挂起,而GDB在等待信号处理。这时候需要检查程序中的信号处理逻辑。 最后,GDB版本或配置的问题,可能需要更新GDB或者检查调试选项是否正确,比如编译时是否加了`-g`选项,是否使用了`-pthread`参数链接线程库。 总结下来,解决步骤可能是: 1. 检查线程状态,使用`info threads`。 2. 尝试在GDB中让所有线程运行,比如`continue`或者调整调度锁。 3. 检查代码中的同步机制,确保子线程有机会执行。 4. 调整断点位置,避免阻塞主线程。 5. 确保GDB设置正确,比如`scheduler-locking`。 6. 检查编译选项和动态库是否正确。</think>在Linux下使用GDB调试多线程程序时卡在创建线程阶段,通常可以通过以下步骤排查和解决: --- ### **1. 确认线程状态** 使用GDB命令查看当前线程状态: ```gdb (gdb) info threads ``` - 如果新线程处于`stopped`状态,可能是GDB默认暂停新线程 - 主线程可能正在等待线程同步(如互斥锁、条件变量等) --- ### **2. 调整GDB线程调度策略** ```gdb (gdb) set scheduler-locking off # 允许所有线程自由运行(默认值) (gdb) set non-stop on # 启用非阻塞模式(需要GDB 7.0+) ``` --- ### **3. 检查常见卡死原因** #### **案例1:线程创建后未执行** ```c // 错误示例:主线程立即退出 int main() { pthread_t tid; pthread_create(&tid, NULL, worker, NULL); return 0; // 主线程退出导致进程终止 } ``` ✅ 解决方案: ```c pthread_join(tid, NULL); // 等待子线程结束 ``` #### **案例2:断点位置不当** - 避免在`pthread_create`调用前设置断点 - 建议在子线程入口函数设置断点: ```gdb (gdb) b worker_thread_func ``` --- ### **4. 动态库加载问题** 使用延迟断点设置: ```gdb (gdb) start (gdb) b pthread_create # 在libpthread加载后设置断点 ``` --- ### **5. 调试技巧** ```gdb (gdb) handle SIG34 pass nostop # 忽略GLIBC内部使用的实时信号 (gdb) set print thread-events on # 显示线程创建/退出事件 (gdb) thread apply all bt # 查看所有线程堆栈 ``` --- ### **6. 编译注意事项** 确保编译命令包含调试信息: ```bash gcc -g -pthread program.c -o program ``` (注意必须使用`-pthread`而非`-lpthread`) --- ### **典型问题处理流程** 1. `run`启动程序 2. 当卡住时按`Ctrl+C`中断 3. 执行`info threads`查看线程状态 4. 检查主线程是否在等待同步机制 5. 使用`thread <ID>`切换线程检查堆栈 6. 通过`stepi`单步执行观察系统调用 --- 如果问题仍然存在,建议: 1. 提供`info threads`的输出 2. 提供主线程和子线程的堆栈跟踪(`bt`命令) 3. 检查是否使用了`fork()`等多进程+多线程混合编程 4. 尝试更新GDB到最新版本(推荐8.3+)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值