set schedular-locking on / off
条件断点查看循环中的某些变量
break if命令
示例:break test.c:34 if (x & y) == 1
默认情况下我们执行到断点处继续执行时,所有线程都会运行。想要控制只有当前线程运行可用上面命令的on实现。
#include <iostream>
#include <thread>
#include <chrono>
void thread1func()
{
while(1)
{
std::cout << "this is thread1, ID: " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void thread2func()
{
while(1)
{
std::cout << "this is thread2, ID: " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main()
{
std::thread thd1(thread1func);
std::thread thd2(thread2func);
std::cout << "this is main thread" << std::endl;
thd1.join();
thd2.join();
return 0;
}
// 编译要添加-g选项
运行程序,命令行查看:
ps -aux / -ef | grep xxx 查看当前运行的进程
[root@localhost ~]# ps -aux | grep a.out
root 4360 0.0 0.1 31240 1108 pts/0 Sl+ 17:20 0:00 ./a.out
root 4366 0.0 0.1 112728 1004 pts/1 S+ 17:21 0:00 grep --color=auto a.out
ps -aL | grep xxx 查看当前运行的轻量级进程(线程)
[root@localhost ~]# ps -aL
PID LWP TTY TIME CMD
4360 4360 pts/0 00:00:00 a.out
4360 4361 pts/0 00:00:00 a.out
4360 4362 pts/0 00:00:00 a.out
4367 4367 pts/1 00:00:00 ps
[root@localhost ~]# ps -aL | grep a.out
4360 4360 pts/0 00:00:00 a.out
4360 4361 pts/0 00:00:00 a.out
4360 4362 pts/0 00:00:00 a.out
pstree -p 主线程id 查看主子线程的关系
[root@localhost ~]# pstree -p 4360
a.out(4360)─┬─{a.out}(4361)
└─{a.out}(4362)
[root@localhost ~]#
线程栈结构的查看
pstack 4360(主线程id)
gdb查看线程信息
gdb attach 主线程id 将进程附加到gdb中,可以看到创建了两个子线程
[root@localhost ~]# gdb attach 4360
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-119.el7
Copyright © 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type “show copying”
and “show warranty” for details.
This GDB was configured as “x86_64-redhat-linux-gnu”.
For bug reporting instructions, please see:
http://www.gnu.org/software/gdb/bugs/…
attach: 没有那个文件或目录.
Attaching to process 4360
Reading symbols from /home/code/cpp考察点/gdb多线程/a.out…(no debugging symbols found)…done.
Reading symbols from /lib64/libpthread.so.0…(no debugging symbols found)…done.
[New LWP 4362]
[New LWP 4361]
[Thread debugging using libthread_db enabled]
Using host libthread_db library “/lib64/libthread_db.so.1”.
Loaded symbols for /lib64/libpthread.so.0
Reading symbols from /lib64/libstdc++.so.6…(no debugging symbols found)…done.
Loaded symbols for /lib64/libstdc++.so.6
查看线程的一些信息
(gdb) info inferiors # 查看进程
Num Description Executable
- 1 process 4360 /home/code/cpp考察点/gdb多线程/a.out
(gdb) info threads # 查看线程
Id Target Id Frame
3 Thread 0x7fc93ccbb700 (LWP 4361) “a.out” 0x00007fc93cd80e2d in nanosleep () from /lib64/libc.so.6
2 Thread 0x7fc93c4ba700 (LWP 4362) “a.out” 0x00007fc93cd80e2d in nanosleep () from /lib64/libc.so.6 - 1 Thread 0x7fc93dcd3740 (LWP 4360) “a.out” 0x00007fc93d8b0f47 in pthread_join () from /lib64/libpthread.so.0
(gdb) bt # 查看线程栈结构
#0 0x00007fc93d8b0f47 in pthread_join () from /lib64/libpthread.so.0
#1 0x00007fc93d655e37 in std::thread::join() () from /lib64/libstdc++.so.6
#2 0x000000000040120b in main ()
(gdb) thread 2 # 切换线程
[Switching to thread 2 (Thread 0x7fc93c4bathread apply all700 (LWP 4362))]
#0 0x00007fc93cd80e2d in nanosleep () from /lib64/libc.so.6
(gdb) thread 3
[Switching to thread 3 (Thread 0x7fc93ccbb700 (LWP 4361))]
#0 0x00007fc93cd80e2d in nanosleep () from /lib64/libc.so.6
(gdb)
gdb调试多线程
设置断点
设置断点 break 行号/函数名
查看断点 info b
执行线程2的函数,执行完毕继续运行到断点处
继续使某线程运行 thread apply 1-n(第几个线程) n
(gdb) break thread1func()
Breakpoint 1 at 0x401101: file main.cc, line 9.
(gdb) thread apply 2 n
只运行当前线程
(gdb) set scheduler-locking on
(gdb) c
所有线程并发执行
(gdb) set scheduler-locking off
(gdb) c
gdb定位死锁
- thread apply all bt 打印所有线程的堆栈信息,观察哪些线程栈卡在lock_wait或者类似调用上,说明这几个线程极有可能产生死锁
- 利用thread ID命令切换到怀疑的线程,打印锁的信息,比如查看线程3,并打印堆栈信息
- 可以看到堆栈最终卡在源码中的第53行,堆栈的第7层,我们使用frame命令查看第7层具体信息
(gdb) frame 7
#7 0x000000000040183f in DataPool::pushToPool (this=0xeab058, inputData=std::shared_ptr (count 2, weak 0) 0x7fdc480008c0) at deadlock.cpp:53
53 std::unique_lockstd::mutex lckTwo(mutexTwo_);
(gdb) - 查看一下lckTwo这把锁和mutexTwo_的信息,Owner字段表示哪个线程持有这把锁,它是线程的lwp号,可以通过info threads查看。
(gdb) p lckTwo
$1 = {_M_device = 0xeab098, M_owns = false}
(gdb) p mutexTwo
$2 = {std::__mutex_base = {_M_mutex = {__data = {__lock = 2, __count = 0, __owner = 18736, __nusers = 1, __kind = 0, __spins = 0, __elision = 0, __list = {__prev = 0x0, __next = 0x0}},
__size = “\002\000\000\000\000\000\000\000\060I\000\000\001”, ‘\000’ <repeats 26 times>, __align = 2}}, }
(gdb)
#这里我们可以看到线程3当前没有拥有lckTwo这把锁,互斥量mutexTwo_当前被lwp号为18736的线程占有,即线程2,那么这个时候我们就找到了死锁的具体点,通过审查线程2执行的代码,死锁很快就能定位出来。我们这段代码是有意地构造死锁条件,进行逆推。不过真实开发中出现的死锁问题,也可以通过gdb调试结合core dump分析来解决。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)