gdb调试分析多线程死锁
转载:
http://blog.chinaunix.net/uid-30343738-id-5757210.html
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h> static int sequence1 = ;
static int sequence2 = ; pthread_mutex_t lock1;
pthread_mutex_t lock2; int func1()
{
pthread_mutex_lock(&lock1);
++sequence1;
sleep();
pthread_mutex_lock(&lock2);
++sequence2;
pthread_mutex_unlock(&lock2);
pthread_mutex_unlock(&lock1); return sequence1;
} int func2()
{
pthread_mutex_lock(&lock2);
++sequence2;
sleep();
pthread_mutex_lock(&lock1);
++sequence2;
pthread_mutex_unlock(&lock1);
pthread_mutex_unlock(&lock2); return sequence1;
} void* thread1(void *arg)
{
int rev = ;
while()
{
rev = func1(); if (rev == )
{
pthread_exit(NULL);
}
}
} void* thread2(void *arg)
{
int rev = ;
while()
{
rev = func2(); if (rev == )
{
pthread_exit(NULL);
}
}
} void* thread3(void *arg)
{
int count = ;
while()
{
sleep();
if ( count++ > )
{
pthread_exit(NULL);
}
}
} void* thread4(void *arg)
{
int count = ;
while()
{
sleep();
if ( count++ > )
{
pthread_exit(NULL);
}
}
} int main()
{
pthread_t tid[]; pthread_mutex_init(&lock1, NULL); pthread_mutex_init(&lock2, NULL); if(pthread_create(&tid[], NULL, &thread1, NULL) != )
{
_exit();
} if(pthread_create(&tid[], NULL, &thread2, NULL) != )
{
_exit();
} if(pthread_create(&tid[], NULL, &thread3, NULL) != )
{
_exit();
} if(pthread_create(&tid[], NULL, &thread4, NULL) != )
{
_exit();
} sleep(); pthread_join(tid[], NULL);
pthread_join(tid[], NULL);
pthread_join(tid[], NULL);
pthread_join(tid[], NULL); pthread_mutex_destroy( &lock1 );
pthread_mutex_destroy( &lock2 ); return ;
}
编译执行程序。
gcc -o main main17.c -lpthread -g
使用 pstack 和 gdb 工具对死锁程序进行分析
1、使用pstack
查找测试程序的进程号
root 5383 1 0 06:31 ? 00:00:43 gedit /root/Project/xa/main17.c
root 7197 7179 0 10:04 pts/1 00:00:00 ./main
root 7218 7206 0 10:04 pts/2 00:00:00 grep --color=auto main
对死锁进程第一次执行 pstack(pstack –进程号)的输出结果
Thread 5 (Thread 0x41e37940 (LWP 6722)):
#0 0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
#2 0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
#3 0x0000000000400a9b in func1() ()
#4 0x0000000000400ad7 in thread1(void*) ()
#5 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
#6 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
Thread 4 (Thread 0x42838940 (LWP 6723)):
#0 0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
#2 0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
#3 0x0000000000400a17 in func2() ()
#4 0x0000000000400a53 in thread2(void*) ()
#5 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
#6 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
Thread 3 (Thread 0x43239940 (LWP 6724)):
#0 0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6
#1 0x0000003d19c9a364 in sleep () from /lib64/libc.so.6
#2 0x00000000004009bc in thread3(void*) ()
#3 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
#4 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
Thread 2 (Thread 0x43c3a940 (LWP 6725)):
#0 0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6
#1 0x0000003d19c9a364 in sleep () from /lib64/libc.so.6
#2 0x0000000000400976 in thread4(void*) ()
#3 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
#4 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
Thread 1 (Thread 0x2b984ecabd90 (LWP 6721)):
#0 0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0
#1 0x0000000000400900 in main ()
对死锁进程第二次执行 pstack(pstack –进程号)的输出结果
Thread 5 (Thread 0x40bd6940 (LWP 6722)):
#0 0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
#2 0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
#3 0x0000000000400a87 in func1() ()
#4 0x0000000000400ac3 in thread1(void*) ()
#5 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
#6 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
Thread 4 (Thread 0x415d7940 (LWP 6723)):
#0 0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
#2 0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
#3 0x0000000000400a03 in func2() ()
#4 0x0000000000400a3f in thread2(void*) ()
#5 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
#6 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
Thread 3 (Thread 0x41fd8940 (LWP 6724)):
#0 0x0000003d19c7aec2 in memset () from /lib64/libc.so.6
#1 0x00000000004009be in thread3(void*) ()
#2 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
#3 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
Thread 2 (Thread 0x429d9940 (LWP 6725)):
#0 0x0000003d19c7ae0d in memset () from /lib64/libc.so.6
#1 0x0000000000400982 in thread4(void*) ()
#2 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
#3 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
Thread 1 (Thread 0x2af906fd9d90 (LWP 6721)):
#0 0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0
#1 0x0000000000400900 in main ()
连续多次查看这个进程的函数调用关系堆栈进行分析:当进程吊死时,多次使用 pstack 查看进程的函数调用堆栈,死锁线程将一直处于等锁的状态,对比多次的函数调用堆栈输出结果,
确定哪两个线程(或者几个线程)一直没有变化且一直处于等锁的状态(可能存在两个线程 一直没有变化)。
输出分析:
根据上面的输出对比可以发现,线程 1 和线程 2 由第一次 pstack 输出的处在 sleep 函数变化为第二次 pstack 输出的处在 memset 函数。但是线程 4 和线程 5 一直处在等锁状态(pthread_mutex_lock),
在连续两次的 pstack 信息输出中没有变化,所以我们可以推测线程 4 和线程 5 发生了死锁
2、使用gdb进行进一步的分析
查找测试程序的进程号
root 5383 1 0 06:31 ? 00:00:43 gedit /root/Project/xa/main17.c
root 7197 7179 0 10:04 pts/1 00:00:00 ./main
root 7218 7206 0 10:04 pts/2 00:00:00 grep --color=auto main
使用gdb 的attach功能
gdb attach 7197
查看当前进程的线程信息
(gdb) info thread
Id Target Id Frame
5 Thread 0xb7539b40 (LWP ) "main" 0xb7717424 in __kernel_vsyscall ()
4 Thread 0xb6d38b40 (LWP ) "main" 0xb7717424 in __kernel_vsyscall ()
3 Thread 0xb6537b40 (LWP ) "main" 0xb7717424 in __kernel_vsyscall ()
2 Thread 0xb5d36b40 (LWP ) "main" 0xb7717424 in __kernel_vsyscall ()
* 1 Thread 0xb753a6c0 (LWP ) "main" 0xb7717424 in __kernel_vsyscall ()
切换到线程 5 的输出
(gdb) thread 5
[Switching to thread 5 (Thread 0xb7539b40 (LWP 7198))]
#0 0xb7717424 in __kernel_vsyscall ()
(gdb) where
#0 0xb7717424 in __kernel_vsyscall ()
#1 0xb76f25a2 in __lll_lock_wait () from /lib/i386-linux-gnu/libpthread.so.0
#2 0xb76edead in _L_lock_686 () from /lib/i386-linux-gnu/libpthread.so.0
#3 0xb76edcf3 in pthread_mutex_lock ()
from /lib/i386-linux-gnu/libpthread.so.0
#4 0x0804864b in func1 () at main17.c:17
#5 0x080486ef in thread1 (arg=0x0) at main17.c:44
#6 0xb76ebd4c in start_thread () from /lib/i386-linux-gnu/libpthread.so.0
#7 0xb762adde in clone () from /lib/i386-linux-gnu/libc.so.6
(gdb) f 4
#4 0x0804864b in func1 () at main17.c:17
warning: Source file is more recent than executable.
17 pthread_mutex_lock(&lock2); ////线程 5 正试图获得锁 lock2
切换到线程4的输出
(gdb) thread 4
[Switching to thread 4 (Thread 0xb6d38b40 (LWP 7199))]
#0 0xb7717424 in __kernel_vsyscall ()
(gdb) where
#0 0xb7717424 in __kernel_vsyscall ()
#1 0xb76f25a2 in __lll_lock_wait () from /lib/i386-linux-gnu/libpthread.so.0
#2 0xb76edead in _L_lock_686 () from /lib/i386-linux-gnu/libpthread.so.0
#3 0xb76edcf3 in pthread_mutex_lock ()
from /lib/i386-linux-gnu/libpthread.so.0
#4 0x080486ae in func2 () at main17.c:30
#5 0x0804871c in thread2 (arg=0x0) at main17.c:58
#6 0xb76ebd4c in start_thread () from /lib/i386-linux-gnu/libpthread.so.0
#7 0xb762adde in clone () from /lib/i386-linux-gnu/libc.so.6
(gdb) f 4
#4 0x080486ae in func2 () at main17.c:30
30 pthread_mutex_lock(&lock1); //线程 4 正试图获得锁 lock1
打印锁的信息
(gdb) p lock1
$1 = {__data = {__lock = 2, __count = 0, __owner = , __kind = 0,
__nusers = 1, {__spins = 0, __list = {__next = 0x0}}},
__size = "\002\000\000\000\000\000\000\000\036\034\000\000\000\000\000\000\001\000\000\000\000\000\000", __align = 2}
(gdb) p lock2
$2 = {__data = {__lock = 2, __count = 0, __owner = , __kind = 0,
__nusers = 1, {__spins = 0, __list = {__next = 0x0}}},
__size = "\002\000\000\000\000\000\000\000\037\034\000\000\000\000\000\000\001\000\000\000\000\000\000", __align = 2}
从上面可以发现,线程 4 正试图获得锁 lock1,但是锁 lock1已经被 LWP 为 7198的线程得到(__owner = 7198),
线程 5 正试图获得锁 lock2,但是锁 lock2 已经被 LWP 为 7199的 得到(__owner = 7199),从 pstack 的输出可以发现(gdb info thread),LWP 7198与线程 5 是对应的,LWP 7199与线程 4 是对应的。
所以我们可以得出, 线程 4 和线程 5 发生了交叉持锁的死锁现象。查看线程的源代码发现,线程 4 和线程 5 同时使用 mutex1 和 mutex2,且申请顺序不合理
gdb调试分析多线程死锁的更多相关文章
- gdb常用命令及使用gdb调试多进程多线程程序
一.常用普通调试命令 1.简单介绍GDB 介绍: gdb是Linux环境下的代码调试⼯具.使⽤:需要在源代码⽣成的时候加上 -g 选项.开始使⽤: gdb binFile退出: ctrl + d 或 ...
- 用gdb调试python多线程代码-记一次死锁的发现
| 版权:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接.如有问题,可以邮件:wangxu198709@gmail.com 前言 相信很多人都有 ...
- gdb调试多进程多线程程序
一.调试的指令 1.list命令 list linenum 显示程序第linenum行的周围的程序 list function 显示程序名为function的函数的源程序 list 显示当前行后面的源 ...
- 通过gdb调试分析Linux内核的启动过程
作者:吴乐 山东师范大学 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验流程 1.打开环境 执 ...
- GDB调试汇编分析
GDB调试汇编分析 代码 本次实践我参照了许多先做了的同学的博客,有卢肖明,高其,张梓靖同学.代码借用的是卢肖明同学的代码进行调试运行. GCC编译 使用gcc -g gdbtest.c -o gdb ...
- 20145233 GDB调试汇编分析
GDB调试汇编分析 代码 #include<stdio.h> short addend1 = 1; static int addend2 = 2; const static long ad ...
- 20145219 gdb调试汇编堆栈分析
20145219 gdb调试汇编堆栈分析 代码gdbdemo.c int g(int x) { return x+19; } int f(int x) { return g(x); } int mai ...
- 20145310 GDB调试汇编堆栈分析
GDB调试汇编堆栈分析 由于老师说要逐条分析汇编代码,所以我学习卢肖明同学的方法,重新写了一篇博客. 代码: #include<stdio.h> short addend1 = 1; st ...
- gdb调试汇编堆栈过程的学习
gdb调试汇编堆栈过程的学习 以下为C源文件 使用gcc - g code.c -o code -m32指令在64位的机器上产生32位汇编,然后使用gdb example指令进入gdb调试器: 进入之 ...
随机推荐
- VIM 使用心得
序 到百度外卖任职以后,发现在我们部门无论 mac 还是 windows,程序员们清一色地都在使用 VIM 来编辑代码,期间穿插着各种插件.快捷键.眼花缭乱的命令.我在大学时只会极少的 VIM 命令, ...
- 【转】linux之cp/scp命令+scp命令详解
linux之cp/scp命令+scp命令详解 名称:cp 使用权限:所有使用者 使用方式: cp [options] source dest cp [options] source... dire ...
- AD快捷键
* 在PCB电气层之间切换.在布线的过程中,按此键则换层并自动添加过孔并换层. Q 在公制和英制之间切换 J+C 定位到指定的元件处.在弹出的对话框内输入该元件的编号. G+G 设定栅格吸附尺寸. T ...
- Python3基础 list remove 删除元素
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- Visual Studio 项目模板制作(四)
上一篇,介绍了VSIX安装模板的方法,那么,你是不是要问,为何有些项目模板却可以有向导,那是怎么做到的 今天这篇文章就是介绍如何为自己的模板添加向导,向导可以引导你完成项目中各种参数的设置,比如项目创 ...
- vs2010中自动给函数或者类加上注释宏模板
Sub AddFunComment() Dim DocSel As EnvDTE.TextSelection DocSel = DTE.ActiveDocument.Selection DocSel. ...
- HDU 6121 Build a tree(完全K叉树)
http://acm.hdu.edu.cn/showproblem.php?pid=6121 题意:给你一颗完全K叉树,求出每棵子树的节点个数的异或和. 思路: 首先需要了解一些关于完全K叉树或满K叉 ...
- UVa 116 单向TSP(多段图最短路)
https://cn.vjudge.net/problem/UVA-116 题意:给出m行n列的整数矩阵,从第一列任何一个位置出发每次往右,右上或右下走一格,最终到达最后一列,要求经过的整数之和最小. ...
- HTTP错误 404.17 - Not Found" IIS 7.5 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理
Errore HTTP 404.2 - Not Found" IIS 7.5 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理 出现这种情况的原因通常是因为先安装了Framewo ...
- python获取文件扩展名的方法
主要介绍了python获取文件扩展名的方法,涉及Python针对文件路径的相关操作技巧 import os.path def file_extension(path): ] print file_ex ...