用法总结
Ubuntu系统,安装cGDB
- sudo apt update
- sudo apt install cgdb
编译代码
- g++ -g -o example example.cpp -lpthread
- 要确保有 -g ,代码是调试信息编译的
启动测试:cgdb ./可执行文件
- 此处可以使用esc进入命令模式,vim命令上下翻页代码
- i 进入命令输入模式
设置断点
- (gdb) break main # 在 main 函数入口处设置断点
- (gdb) break MyService::Start # 在 MyService::Start 函数处设置断点
- (gdb) break 42 # 在第 42 行设置断点
- (gdb) info breakpoints # 显示所有断点信息
控制断点
- (gdb) disable 1 # 禁用编号为 1 的断点
- (gdb) enable 1 # 启用编号为 1 的断点
- (gdb) delete 1 # 删除编号为 1 的断点
运行程序(设置好断点后,就可以运行程序开始调试了)
- (gdb) run # 运行程序
执行控制(截图演示,一张命令行截图+一张UI界面显式截图)
- (gdb) step # 单步执行,进入函数内部
- (gdb) next # 单步执行,不进入函数内部
- (gdb) finish # 运行到当前函数结束
- (gdb) continue # 继续运行到下一个断点或程序结束
修改变量(后面事例演示)
- (gdb) set var = value # 设置变量 var 的值为 value
多线程调试(后续事例演示)
- (gdb) info threads # 显示所有线程
- (gdb) thread 2 # 切换到线程 2
- (gdb) thread apply all bt # 对所有线程执行 backtrace
退出GDB
- quit
//上述事例测试代码
#include <functional>
#include <iostream>
#include <thread>
#include <chrono>
#include <vector>
class TimerTask {
public:
TimerTask(int id, std::function<void()> callback)
: task_id(id), task_callback(callback) {}
void execute() {
if (task_callback) {
task_callback();
}
}
int get_id() const { return task_id; }
private:
int task_id;
std::function<void()> task_callback;
};
class TimerScheduler {
public:
void add_task(int delay_sec, int id, std::function<void()> callback) {
tasks.emplace_back(id, callback);
std::thread([this, delay_sec, id]() {
std::this_thread::sleep_for(std::chrono::seconds(delay_sec));
this->execute_task(id);
}).detach();
}
void execute_task(int id) {
for (auto& task : tasks) {
if (task.get_id() == id) {
task.execute();
break;
}
}
}
void run() {
// Simulate running scheduler
}
private:
std::vector<TimerTask> tasks;
};
class MyService {
public:
MyService(TimerScheduler& scheduler) : scheduler(scheduler) {}
void start() {
auto task = std::bind(&MyService::task_callback, this, std::placeholders::_1);
scheduler.add_task(5, 1, std::bind(task, 42));
}
void task_callback(int value) {
std::cout << "Task executed with value: " << value << std::endl;
}
private:
TimerScheduler& scheduler;
};
int main() {
TimerScheduler scheduler;
MyService service(scheduler);
service.start();
scheduler.run();
std::this_thread::sleep_for(std::chrono::seconds(10)); // Simulate running
return 0;
}
使用事例
调试代码一:简单的多线程调试方法
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
void thread_function(int id) {
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Thread " << id << " finished execution." << std::endl;
}
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 5; ++i) {
threads.emplace_back(thread_function, i);
}
for (auto& t : threads) {
t.join();
}
return 0;
}
设置断点并运行程序
- (gdb) break main
- (gdb) run
单步执行同时查看变量的变化
- (gdb) step
- (gdb) next
- (gdb) info locals
查看所有线程(此时再执行创建线程的循环中,目前已经创建了两个线程)
- (gdb) info threads
切换到指定线程,并在该线程中单步执行
- (gdb) thread 3
对所有线程执行回溯 (gdb) thread apply all bt
调试代码二:复杂线程下的调试
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
#include <mutex>
std::mutex mtx;
void thread_function(int id) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Thread " << id << " acquired the lock." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Thread " << id << " released the lock." << std::endl;
}
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 3; ++i) {
threads.emplace_back(thread_function, i);
}
for (auto& t : threads) {
t.join();
}
return 0;
}
设置断点开始调试
- (gdb) break thread_function
- (gdb) run
在thread_function函数入口查看所有线程
切换到线程4,然后再线程4中单步执行程序(step) ,查看并修改4号线程的id变量
- (gdb) print id
- (gdb) set id = 19
- (gdb) print id
最后退出调试即可quit