• Linux下gdb attach的使用(调试已在运行的进程)


    在Linux上,执行有多线程的程序时,当程序执行退出操作时有时会遇到卡死现象,如果程序模块多,代码量大,很难快速定位,此时可试试gdb attach方法。

    测试代码main.cpp如下,这里为了使程序退出时产生卡死现象,在第51行时push线程sleep 100分钟:

    1. #include <stdio.h>
    2. #include <thread>
    3. #include <queue>
    4. #include <mutex>
    5. #include <condition_variable>
    6. #include <chrono>
    7. namespace {
    8. class Queue {
    9. public:
    10. Queue() = default;
    11. ~Queue() { }
    12. void Init(int num) {
    13. for (int i = 0; i < num; ++i) {
    14. queue_.push(i);
    15. }
    16. }
    17. int Pop() {
    18. std::unique_lock<std::mutex> lck(mutex_);
    19. while (queue_.size() == 0) {
    20. cv_.wait(lck);
    21. }
    22. int value = queue_.front();
    23. queue_.pop();
    24. return value;
    25. }
    26. void Push(int value) {
    27. std::unique_lock<std::mutex> lck(mutex_);
    28. queue_.push(value);
    29. cv_.notify_all();
    30. }
    31. private:
    32. std::queue<int> queue_;
    33. std::mutex mutex_;
    34. std::condition_variable cv_;
    35. }; // class Queue
    36. bool running = false;
    37. void push(Queue& q) {
    38. int value = 100;
    39. while (running) {
    40. q.Push(value++);
    41. std::this_thread::sleep_for(std::chrono::minutes(100));
    42. }
    43. }
    44. void pop(Queue& q) {
    45. while (running) {
    46. fprintf(stdout, "pop value: %d ", q.Pop());
    47. std::this_thread::sleep_for(std::chrono::seconds(1));
    48. }
    49. }
    50. } // namespace
    51. int main()
    52. {
    53. fprintf(stdout, "test start ");
    54. Queue q;
    55. q.Init(2);
    56. running = true;
    57. std::thread th1(push, std::ref(q));
    58. std::thread th2(pop, std::ref(q));
    59. std::this_thread::sleep_for(std::chrono::seconds(10));
    60. running = false;
    61. th1.join();
    62. th2.join();
    63. fprintf(stdout, "test end ");
    64. return 0;
    65. }

    build.sh脚本内容如下:

    1. g++ -g -std=c++11 -o main main.cpp -lpthread
    2. ./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));语句上,分析完成,了解了程序卡死的原因,执行结果如下图所示:

    GitHubhttps://github.com/fengbingchun/Messy_Test

  • 相关阅读:
    Bugly和dispatch_once Crash
    IQKeyboardManager
    Storyboard References
    Book
    Git管理
    iOS开发之RunLoop--转
    H264之PPS、SPS了解
    iOS之UI设置随记
    使用 github 本地项目上传到github上 步骤
    spring中自定义注解
  • 原文地址:https://www.cnblogs.com/xiuzhublog/p/13784057.html
Copyright © 2020-2023  润新知