RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 771275
Accepted
xperious
xperious
Asked:2020-01-16 06:34:53 +0000 UTC2020-01-16 06:34:53 +0000 UTC 2020-01-16 06:34:53 +0000 UTC

gdb 调试多线程应用程序

  • 772

你好,有必要学习如何通过gdb调试多线程应用程序......假设有这样一个应用程序有几个线程:

int main() {
     static int i =0;
     std::thread([](){ while(true) { ++i; std::this_thread::sleep_for( std::chrono::milliseconds(700)); std::cout << "hello\n";}}).detach();
     std::thread([](){ while(true) { std::this_thread::sleep_for(std::chrono::milliseconds(600)); std::cout << "my\n";}}).detach();
     std::thread([](){ while(true) { std::this_thread::sleep_for(std::chrono::milliseconds(900)); std::cout << "world\n";}}).detach();
     std::thread([](){ while(true) { std::this_thread::sleep_for(std::chrono::milliseconds(700)); std::cout << "ro\n";}}).join();
}

连接 gdb -p number_of_pid 进程:

Type "apropos word" to search for commands related to "word".
Attaching to process 9208
[New LWP 9209]
[New LWP 9210]
[New LWP 9211]
[New LWP 9212]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
0x00007f1bae990acd in pthread_join () from /lib64/libpthread.so.0

并且应用程序停止...告诉我如何在调试器中查看变量 i 的值,如果我们一附加 gdb,那么一切都停止,如果我们接下来执行,那么假设某行中的 br,然后n,然后一切顺利 和以前一样,变量 i 的值(通过打印)无法显示...

c++
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    Fat-Zer
    2020-01-16T07:34:45Z2020-01-16T07:34:45Z

    给年轻情妇的基本注意事项

    对于调试(至少对于舒适的调试),有必要使用调试信息进行构建,在 gcc 中,密钥用于-g:

    g++ -pthread -g thr.cpp -o thr
    

    您可以立即在 gdb 下启动该进程:

    gdb ./thr
    

    或绑定到已经运行的进程:

    gdb -p <pid_of_already_running_process>
    

    在第一种情况下,启动调试器后,必须使用命令run或启动进程本身r

    (gdb) r
    Starting program: /tmp/thr
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib64/libthread_db.so.1".
    [New Thread 0x7ffff6ee0700 (LWP 27964)]
    [New Thread 0x7ffff66df700 (LWP 27965)]
    [New Thread 0x7ffff5ede700 (LWP 27966)]
    [New Thread 0x7ffff56dd700 (LWP 27967)]
    my
    hello
    ro
    world
    .......
    

    可以随时SIGINT使用 'om 或换句话说Ctrl+暂停该过程C。

    定义设置

    在任意点停止后,值得看看我们在哪里,为此有命令backtrace( b) 和info threads( i th)

    Thread 1 "thr" received signal SIGINT, Interrupt.
    0x00007ffff729a93d in pthread_join () from /lib64/libpthread.so.0
    (gdb) bt
    #0  0x00007ffff729a93d in pthread_join () from /lib64/libpthread.so.0
    #1  0x00007ffff7ab7537 in std::thread::join() () from /usr/lib/gcc/x86_64-pc-linux-gnu/6.4.0/libstdc++.so.6
    #2  0x0000555555555310 in main () at thr.cpp:13
    (gdb) i th
      Id   Target Id         Frame
    * 1    Thread 0x7ffff7f7d740 (LWP 28093) "thr" 0x00007ffff729a93d in pthread_join () from /lib64/libpthread.so.0
      2    Thread 0x7ffff6ee0700 (LWP 28097) "thr" 0x00007ffff72a4e4d in nanosleep () from /lib64/libpthread.so.0
      3    Thread 0x7ffff66df700 (LWP 28098) "thr" 0x00007ffff72a4e4d in nanosleep () from /lib64/libpthread.so.0
      4    Thread 0x7ffff5ede700 (LWP 28099) "thr" 0x00007ffff72a4e4d in nanosleep () from /lib64/libpthread.so.0
      5    Thread 0x7ffff56dd700 (LWP 28100) "thr" 0x00007ffff72a4e4d in nanosleep () from /lib64/libpthread.so.0
    

    如您所见,gdb 现在位于pthread_join()主线程的上下文中。

    堆栈框架变化和可变打印

    要打印变量(print),您需要切换到它所在的框架,为此有一个命令frame(f),同时您可以看到列表(list):

    (gdb) f 2
    #2  0x0000555555555310 in main () at thr.cpp:13
    13           std::thread([](){ while(true) { std::this_thread::sleep_for(std::chrono::milliseconds(700)); std::cout << "ro\n";}}).join();
    (gdb) l
    8                    std::this_thread::sleep_for( std::chrono::milliseconds(700));
    9                    std::cout << "hello\n";}
    10                   }).detach();
    11           std::thread([](){ while(true) { std::this_thread::sleep_for(std::chrono::milliseconds(600)); std::cout << "my\n";}}).detach();
    12           std::thread([](){ while(true) { std::this_thread::sleep_for(std::chrono::milliseconds(900)); std::cout << "world\n";}}).detach();
    13           std::thread([](){ while(true) { std::this_thread::sleep_for(std::chrono::milliseconds(700)); std::cout << "ro\n";}}).join();
    14      }
    (gdb) p i
    $1 = 3
    

    其中 2 inframe 2是输出中感兴趣的帧的数量bt。

    单步穿流

    要逐步调试特定线程,您需要使用命令thread( thr) 将 gdb 切换到其上下文:

    (gdb) thread 2
    [Switching to thread 2 (Thread 0x7ffff6ee0700 (LWP 28097))]
    #0  0x00007ffff72a4e4d in nanosleep () from /lib64/libpthread.so.0
    

    每个线程都有自己的栈,所以再看一遍也不会是多余的backtrace,如果有必要,跳转到想要的帧。

    (gdb) bt
    #0  0x00007ffff72a4e4d in nanosleep () from /lib64/libpthread.so.0
    #1  0x0000555555556aa7 in std::this_thread::sleep_for<long, std::ratio<1l, 1000l> > (__rtime=...) at /usr/lib/gcc/x86_64-pc-linux-gnu/6.4.0/include/g++-v6/thread:323
    #2  0x0000555555555140 in <lambda()>::operator()(void) const (__closure=0x55555576bc28) at thr.cpp:8
    #3  0x0000555555556524 in std::_Bind_simple<main()::<lambda()>()>::_M_invoke<>(std::_Index_tuple<>) (this=0x55555576bc28) at /usr/lib/gcc/x86_64-pc-linux-gnu/6.4.0/include/g++-v6/functional:1391
    #4  0x0000555555556394 in std::_Bind_simple<main()::<lambda()>()>::operator()(void) (this=0x55555576bc28) at /usr/lib/gcc/x86_64-pc-linux-gnu/6.4.0/include/g++-v6/functional:1380
    #5  0x0000555555556292 in std::thread::_State_impl<std::_Bind_simple<main()::<lambda()>()> >::_M_run(void) (this=0x55555576bc20) at /usr/lib/gcc/x86_64-pc-linux-gnu/6.4.0/include/g++-v6/thread:197
    #6  0x00007ffff7ab724e in ?? () from /usr/lib/gcc/x86_64-pc-linux-gnu/6.4.0/libstdc++.so.6
    #7  0x00007ffff7299657 in start_thread () from /lib64/libpthread.so.0
    #8  0x00007ffff6fd9c5f in clone () from /lib64/libc.so.6
    

    之后,您可以使用next/ step( n/ s) 以通常的方式调试流:

    (gdb) n
    Single stepping until exit from function nanosleep,
    which has no line number information.
    my
    world
    ro
    std::this_thread::sleep_for<long, std::ratio<1l, 1000l> > (__rtime=...) at /usr/lib/gcc/x86_64-pc-linux-gnu/6.4.0/include/g++-v6/thread:328
    328           }
    (gdb)
    my
    world
    ro
    <lambda()>::operator()(void) const (__closure=0x55555576bc28) at thr.cpp:9
    9                    std::cout << "hello\n";}
    (gdb)
    my
    ro
    world
    hello
    7                    ++i;
    (gdb)
    my
    world
    ro
    8                    std::this_thread::sleep_for( std::chrono::milliseconds(700));
    (gdb)
    world
    my
    ro
    my
    ro
    9                    std::cout << "hello\n";}
    (gdb)
    my
    world
    ro
    hello
    7                    ++i;
    (gdb)
    my
    world
    ro
    8                    std::this_thread::sleep_for( std::chrono::milliseconds(700));
    (gdb) p i
    $2 = 5
    

    有几点值得一提:

    • 为了逐步调试,代码已经稍微重新格式化,如您在上面的清单中所见。
    • 关于多线程应用程序:当控制权返回给进程时,n所有线程都立即启动,因此您几乎可以在每个命令之后看到额外的输出。

    对于后续阅读/查看,我推荐至少入门“使用 GDB 调试”

    • 10

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5