天天看点

g-gdb 调试多线程

代码调试工具gdb是一个能够让我们在工作中高效排查代码异常根源的利器。

在此将gdb针对多线程的调试方式做一个笔记,也方便后续回顾以及分享大家。

本文采用的是一个简单的多线程代码示例,同时调试是在mac上进行的

mac安装gdb ​​

​brew install gdb​

​即可

基本命令介绍

开始之前先简单介绍几个gdb调试多线程的子命令

  • layout next 开启子窗口,显示当前程序运行所在的源码位置
  • b xxx 在某一行,或者某一个函数处增加断点
  • info b 查看断点信息
  • r 运行程序
  • info threads 查看当前可调试的所有线程信息
  • where 查看进程运行到当前位置的函数调用栈信息
  • thread num 调试状态切换到线程num
  • break thread_test.cc:123 thread all 在所有线程中相应的行上设置断点
  • thread apply all id1 id2 command 让一个或者多个线程执行GDB命令
  • thread apply all command 让所有被调试线程执行gdb命令 command
  • watch variable 在断点当前位置增加变量的variable的监控信息,后续运行的时候会打印
  • c 继续运行,直到遇到断点停顿

示例1

目标:在不加锁的情况下,多个线程的运行交叉运行的,导致进程内部共享的变量对外的体现不是连续的。

代码如下

#include <iostream>
#include <thread>
#include <mutex>

using namespace std;

static int g_a = 0;

void pthread_func1() {
    for (int i = 1;i < 5000; ++i) {
        g_a ++;
    }
}

void pthread_func2() {
    for (int i = 5000;i < 10000; ++i) {
        g_a ++;
    }
}

int main() {
    thread t1(pthread_func1);
    thread t2(pthread_func2);

    t1.join();
    t2.join();
    return 0;
}      

编译:

​g++ -std=c++11 -g pthread_test.cc -o pthread_test -pthread​

​ 调试过程如下:

g-gdb 调试多线程

通过以上调试我们可以发现在当前进程中的变量g_a每运行一次并不是累加1,可能会累加2,而且代码的跳转也能发现其实是多个线程交替执行。

基本的调试方式也就是使用我们已经说过的线程相关调试命令了。

示例2

目标:在加锁的情况下,我们的进程全局变量的访问变成了串行方式

测试代码如下:

#include <iostream>
#include <thread>
#include <mutex>

using namespace std;

mutex g_lock;
static int g_a = 0;

void pthread_func1() {
    for (int i = 1;i < 5000; ++i) {
        g_lock.lock();
        g_a ++;
        g_lock.unlock();
    }
}

void pthread_func2() {
    for (int i = 5000;i < 10000; ++i) {
        g_lock.lock();
        g_a ++;
        g_lock.unlock();
    }
}

int main() {
    thread t1(pthread_func1);
    thread t2(pthread_func2);

    t1.join();
    t2.join();
    return 0;
}      

编译调试过程如下:

g-gdb 调试多线程

总结