代碼調試工具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_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;
}
編譯調試過程如下: