千家信息网

Linux系统分析死锁的方法是什么

发表于:2024-11-16 作者:千家信息网编辑
千家信息网最后更新 2024年11月16日,这篇文章主要介绍"Linux系统分析死锁的方法是什么",在日常操作中,相信很多人在Linux系统分析死锁的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Lin
千家信息网最后更新 2024年11月16日Linux系统分析死锁的方法是什么

这篇文章主要介绍"Linux系统分析死锁的方法是什么",在日常操作中,相信很多人在Linux系统分析死锁的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Linux系统分析死锁的方法是什么"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

产生死锁的四个必要条件

(1) 互斥条件:一个资源每次只能被一个进程(线程)使用。

(2) 请求与保持条件:一个进程(线程)因请求资源而阻塞时,对已获得的资源保持不放。

(3) 不剥夺条件 : 此进程(线程)已获得的资源,在末使用完之前,不能强行剥夺。

(4) 循环等待条件 : 多个进程(线程)之间形成一种头尾相接的循环等待资源关系。

图 1. 交叉持锁的死锁示意图:

注释:在执行 func2 和 func4 之后,子线程 1 获得了锁 A,正试图获得锁 B,但是子线程 2 此时获得了锁 B,正试图获得锁 A,所以子线程 1 和子线程 2 将没有办法得到锁 A 和锁 B,因为它们各自被对方占有,永远不会释放,所以发生了死锁的现象。

使用 pstack 和 gdb 工具对死锁程序进行分析

pstack 在 Linux 平台上的简单介绍

pstack 是 Linux(比如 Red Hat Linux 系统、Ubuntu Linux 系统等)下一个很有用的工具,它的功能是打印输出此进程的堆栈信息。可以输出所有线程的调用关系栈。

gdb 在 Linux 平台上的简单介绍

GDB 是 GNU 开源组织发布的一个强大的 UNIX 下的程序调试工具。Linux 系统中包含了 GNU 调试程序 gdb,它是一个用来调试 C 和 C++ 程序的调试器。可以使程序开发者在程序运行时观察程序的内部结构和内存的使用情况 .

gdb 所提供的一些主要功能如下所示:

1 运行程序,设置能影响程序运行的参数和环境 ;

2 控制程序在指定的条件下停止运行;

3 当程序停止时,可以检查程序的状态;

4 当程序 crash 时,可以检查 core 文件;

5 可以修改程序的错误,并重新运行程序;

6 可以动态监视程序中变量的值;

7 可以单步执行代码,观察程序的运行状态。

gdb 程序调试的对象是可执行文件或者进程,而不是程序的源代码文件。然而,并不是所有的可执行文件都可以用 gdb 调试。如果要让产生的可执行文件可以用来调试,需在执行 g++(gcc)指令编译程序时,加上 -g 参数,指定程序在编译时包含调试信息。调试信息包含程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。gdb 利用这些信息使源代码和机器码相关联。gdb 的基本命令较多,不做详细介绍,大家如果需要进一步了解,请参见 gdb 手册。

清单 1. 测程序

  #include  #include  #include   pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;  pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;  pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;  pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER;   static int sequence1 = 0;  static int sequence2 = 0;   int func1()  {     pthread_mutex_lock(&mutex1);     ++sequence1;     sleep(1);     pthread_mutex_lock(&mutex2);     ++sequence2;     pthread_mutex_unlock(&mutex2);     pthread_mutex_unlock(&mutex1);      return sequence1;  }   int func2()  {     pthread_mutex_lock(&mutex2);     ++sequence2;     sleep(1);     pthread_mutex_lock(&mutex1);     ++sequence1;     pthread_mutex_unlock(&mutex1);     pthread_mutex_unlock(&mutex2);      return sequence2;  }   void* thread1(void* arg)  {     while (1)     {         int iRetValue = func1();          if (iRetValue == 100000)         {             pthread_exit(NULL);         }     }  }   void* thread2(void* arg)  {     while (1)     {         int iRetValue = func2();          if (iRetValue == 100000)         {             pthread_exit(NULL);         }     }  }   void* thread3(void* arg)  {     while (1)     {         sleep(1);         char szBuf[128];         memset(szBuf, 0, sizeof(szBuf));         strcpy(szBuf, "thread3");     }  }   void* thread4(void* arg)  {     while (1)     {         sleep(1);         char szBuf[128];         memset(szBuf, 0, sizeof(szBuf));         strcpy(szBuf, "thread3");     }  }   int main()  {     pthread_t tid[4];     if (pthread_create(&tid[0], NULL, &thread1, NULL) != 0)     {         _exit(1);     }     if (pthread_create(&tid[1], NULL, &thread2, NULL) != 0)     {         _exit(1);     }     if (pthread_create(&tid[2], NULL, &thread3, NULL) != 0)     {         _exit(1);     }     if (pthread_create(&tid[3], NULL, &thread4, NULL) != 0)     {         _exit(1);     }      sleep(5);     //pthread_cancel(tid[0]);      pthread_join(tid[0], NULL);     pthread_join(tid[1], NULL);     pthread_join(tid[2], NULL);     pthread_join(tid[3], NULL);      pthread_mutex_destroy(&mutex1);     pthread_mutex_destroy(&mutex2);     pthread_mutex_destroy(&mutex3);     pthread_mutex_destroy(&mutex4);      return 0;  }

清单 2. 编译测试程序

  [dyu@xilinuxbldsrv purify]$ g++ -g lock.cpp -o lock -lpthread

清单 3. 查找测试程序的进程号

  [dyu@xilinuxbldsrv purify]$ ps -ef|grep lock  dyu       6721  5751  0 15:21 pts/3    00:00:00 ./lock

清单 4. 对死锁进程第一次执行 pstack(pstack –进程号)的输出结果

 [dyu@xilinuxbldsrv purify]$ pstack 6721  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 ()       清单 5. 对死锁进程第二次执行 pstack(pstack –进程号)的输出结果       [dyu@xilinuxbldsrv purify]$ pstack 6721  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 ()

清单 5. 对死锁进程第二次执行 pstack(pstack –进程号)的输出结果

 [dyu@xilinuxbldsrv purify]$ pstack 6721  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 发生了死锁。

 Gdb into thread``输出:

清单 6. 然后通过 gdb attach 到死锁进程

  (gdb) info thread   5 Thread 0x41e37940 (LWP 6722)  0x0000003d1a80d4c4 in __lll_lock_wait ()   from /lib64/libpthread.so.0   4 Thread 0x42838940 (LWP 6723)  0x0000003d1a80d4c4 in __lll_lock_wait ()   from /lib64/libpthread.so.0   3 Thread 0x43239940 (LWP 6724)  0x0000003d19c9a541 in nanosleep ()  from /lib64/libc.so.6   2 Thread 0x43c3a940 (LWP 6725)  0x0000003d19c9a541 in nanosleep ()  from /lib64/libc.so.6  * 1 Thread 0x2b984ecabd90 (LWP 6721)  0x0000003d1a807b35 in pthread_join ()  from /lib64/libpthread.so.0

清单 7. 切换到线程 5 的输出

 (gdb) thread 5  [Switching to thread 5 (Thread 0x41e37940 (LWP 6722))]#0  0x0000003d1a80d4c4 in  __lll_lock_wait () from /lib64/libpthread.so.0  (gdb) where  #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 () at lock.cpp:18  #4  0x0000000000400ad7 in thread1 (arg=0x0) at lock.cpp:43  #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0  #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6

清单 8. 线程 4 和线程 5 的输出

  (gdb) f 3  #3  0x0000000000400a9b in func1 () at lock.cpp:18  18          pthread_mutex_lock(&mutex2);  (gdb) thread 4  [Switching to thread 4 (Thread 0x42838940 (LWP 6723))]#0  0x0000003d1a80d4c4 in  __lll_lock_wait () from /lib64/libpthread.so.0  (gdb) f 3  #3  0x0000000000400a17 in func2 () at lock.cpp:31  31          pthread_mutex_lock(&mutex1);  (gdb) p mutex1  $1 = {__data = {__lock = 2, __count = 0, __owner = 6722, __nusers = 1, __kind = 0,  __spins = 0, __list = {__prev = 0x0, __next = 0x0}},   __size = "\002\000\000\000\000\000\000\000B\032\000\000\001", '\000'  , __align = 2}  (gdb) p mutex3  $2 = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0,  __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}},  __size = '\000', __align = 0}  (gdb) p mutex2  $3 = {__data = {__lock = 2, __count = 0, __owner = 6723, __nusers = 1,  __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}},   __size = "\002\000\000\000\000\000\000\000C\032\000\000\001", '\000'  , __align = 2}  (gdb)

从上面可以发现,线程 4 正试图获得锁 mutex1,但是锁 mutex1 已经被 LWP 为 6722 的线程得到(owner = 6722),线程 5 正试图获得锁 mutex2,但是锁 mutex2 已经被 LWP 为 6723 的 得到(owner = 6723),从 pstack 的输出可以发现,LWP 6722 与线程 5 是对应的,LWP 6723 与线程 4 是对应的。所以我们可以得出, 线程 4 和线程 5 发生了交叉持锁的死锁现象。查看线程的源代码发现,线程 4 和线程 5 同时使用 mutex1 和 mutex2,且申请顺序不合理。

到此,关于"Linux系统分析死锁的方法是什么"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

线程 程序 进程 死锁 输出 清单 系统 分析 信息 文件 条件 运行 方法 函数 状态 资源 堆栈 源代码 结果 变化 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 可以用手机玩的神奇宝贝服务器 软件开发北京找工作 网络安全里面什么是安全区域 攀枝花服务器数据迁移 网络安全隐患2007 魔兽世界6.0服务器平衡 临沂盘古网络技术有限公司 下一代网络技术的核心 智能互联网络技术属于计算机吗 邮件服务器的安全管理 我与网络安全有个约定手抄报幼儿 秦皇岛网络技术市场报价 ios显示服务器图片 怀旧服服务器战士哪个职业好 计算机三级网络技术手机题库 计算机网络技术职业规划ppt 软件开发技术方案编写 热门云服务器招商项目 标准网络技术服务怎么样 邮箱发送文件夹服务器连接错误 数据库停止不能运行 计算机网络技术是电子信息类吗 人机交互软件开发 非关系型数据库查询数据的区别 永宁游戏软件开发 oracle数据库逻辑结构顺序 工行软件开发中网址 大学生人网络安全ppt 我的世界梦之岛服务器 ibm服务器如何重启
0