天天看點

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 調試多線程

總結