在Linux上,執行有多線程的程序時,當程序執行退出操作時有時會遇到卡死現象,如果程序模塊多,代碼量大,很難快速定位,此時可試試gdb attach方法。
測試代碼main.cpp如下,這里為了使程序退出時產生卡死現象,在第51行時push線程sleep 100分鍾:
-
#include <stdio.h>
-
#include <thread>
-
#include <queue>
-
#include <mutex>
-
#include <condition_variable>
-
#include <chrono>
-
-
namespace {
-
-
class Queue {
-
public:
-
Queue() =
default;
-
~Queue() { }
-
-
void Init(int num) {
-
for (
int i =
0; i < num; ++i) {
-
queue_.push(i);
-
}
-
}
-
-
int Pop() {
-
std::unique_lock<std::mutex> lck(mutex_);
-
while (queue_.size() ==
0) {
-
cv_.wait(lck);
-
}
-
-
int value = queue_.front();
-
queue_.pop();
-
-
return value;
-
}
-
-
void Push(int value) {
-
std::unique_lock<std::mutex> lck(mutex_);
-
queue_.push(value);
-
cv_.notify_all();
-
}
-
-
private:
-
std::
queue<
int> queue_;
-
std::mutex mutex_;
-
std::condition_variable cv_;
-
};
// class Queue
-
-
bool running =
false;
-
-
void push(Queue& q) {
-
int value =
100;
-
while (running) {
-
q.Push(value++);
-
std::this_thread::sleep_for(
std::chrono::minutes(
100));
-
}
-
}
-
-
void pop(Queue& q) {
-
while (running) {
-
fprintf(
stdout,
"pop value: %d\n", q.Pop());
-
std::this_thread::sleep_for(
std::chrono::seconds(
1));
-
}
-
}
-
-
}
// namespace
-
-
int main()
-
{
-
fprintf(
stdout,
"test start\n");
-
-
Queue q;
-
q.Init(
2);
-
-
running =
true;
-
std::thread th1(push, std::ref(q));
-
std::thread th2(pop, std::ref(q));
-
-
std::this_thread::sleep_for(
std::chrono::seconds(
10));
-
running =
false;
-
th1.join();
-
th2.join();
-
-
fprintf(
stdout,
"test end\n");
-
return
0;
-
}
build.sh腳本內容如下:
-
g++ -g -std=c++11 -o main main.cpp -lpthread
-
./main
執行:$ ./build.sh ,執行結果如下,程序無法正常退出,產生卡死現象:
通過命令:$ ps -aux | grep main ,獲取執行main的進程(pid),如下圖所示,執行main的進程為18786:
啟動gdb attach,執行gdb attach pid即可調試正在運行的程序,執行:$ gdb attach 18786,若執行gdb attach時提示:” ptrace: Operation not permitted”,則執行:$ sudo gdb attach 18786,如下圖所示:
也可執行:$ gdb main 18786,與gdb attach 18786相同。
常用的命令如下:
1. bt:查看函數調用棧的所有信息,當程序執行異常時,可通過此命令查看程序的調用過程;
2. info threads:顯示當前進程中的線程;
3. thread id:切換到具體的線程id,一般切換到具體的線程后再執行bt等操作。
首先執行info threads,發現共有3個線程,當前線程id是1,即主線程,執行bt,會發現程序卡在第77行,即th1.join()語句上,即在push函數內沒有退出;執行thread 2,再執行bt,發現此線程在執行pop函數,卡在了第24行的cv_.wait(lck)語句上;執行thread 3,再執行bt,發現此線程在執行push函數,卡在了第51行的std::this_thread::sleep_for(std::chrono::minutes(100));語句上,分析完成,了解了程序卡死的原因,執行結果如下圖所示: