请选择 进入手机版 | 继续访问电脑版

[LINUX] 在Linux平台下分析死锁标题 的方法

[复制链接]
查看142 | 回复12 | 2021-9-5 03:14:26 | 显示全部楼层 |阅读模式

死锁 (deallocks): 是指两个或两个以上的进程 (线程)在实行 过程中,因夺取 资源而造成的一种互相称 待的征象 ,若无外力作用,它们都将无法推进下去。此时称体系 处于死锁状态或体系 产生了死锁,这些永世 在互相称 待的进程 (线程)称为死锁进程 (线程)。 由于资源占用是互斥的,当某个进程 提出申请资源后,使得有关进程 (线程)在无外力帮忙 下,永世 分配不到必需的资源而无法继续运行,这就产生了一种特别 征象 死锁。

一种交叉持锁死锁的情况 ,此时实行 程序中两个或多个线程发生永世 堵塞(等待),每个线程都在等待被别的 线程占用并堵塞了的资源。比方 ,假如 线程 1 锁住了记录 A 并等待记录 B,而线程 2 锁住了记录 B 并等待记录 A,如许 两个线程就发生了死锁征象 。在计算机体系 中 , 假如 体系 的资源分配策略不当,更常见的大概 是程序员写的程序有错误等,则会导致进程 因竞争资源不当而产存亡 锁的征象 。

产存亡 锁的四个必要条件

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

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

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

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

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

在Linux平台下分析死锁标题

的方法

表明 :在实行 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. 测试程序

  1. #include
  2. #include
  3. #include
  4. pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
  5. pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
  6. pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;
  7. pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER;
  8. static int sequence1 = 0;
  9. static int sequence2 = 0;
  10. int func1()
  11. {
  12. pthread_mutex_lock(&mutex1);
  13. ++sequence1;
  14. sleep(1);
  15. pthread_mutex_lock(&mutex2);
  16. ++sequence2;
  17. pthread_mutex_unlock(&mutex2);
  18. pthread_mutex_unlock(&mutex1);
  19. return sequence1;
  20. }
  21. int func2()
  22. {
  23. pthread_mutex_lock(&mutex2);
  24. ++sequence2;
  25. sleep(1);
  26. pthread_mutex_lock(&mutex1);
  27. ++sequence1;
  28. pthread_mutex_unlock(&mutex1);
  29. pthread_mutex_unlock(&mutex2);
  30. return sequence2;
  31. }
  32. void* thread1(void* arg)
  33. {
  34. while (1)
  35. {
  36. int iRetValue = func1();
  37. if (iRetValue == 100000)
  38. {
  39. pthread_exit(NULL);
  40. }
  41. }
  42. }
  43. void* thread2(void* arg)
  44. {
  45. while (1)
  46. {
  47. int iRetValue = func2();
  48. if (iRetValue == 100000)
  49. {
  50. pthread_exit(NULL);
  51. }
  52. }
  53. }
  54. void* thread3(void* arg)
  55. {
  56. while (1)
  57. {
  58. sleep(1);
  59. char szBuf[128];
  60. memset(szBuf, 0, sizeof(szBuf));
  61. strcpy(szBuf, "thread3");
  62. }
  63. }
  64. void* thread4(void* arg)
  65. {
  66. while (1)
  67. {
  68. sleep(1);
  69. char szBuf[128];
  70. memset(szBuf, 0, sizeof(szBuf));
  71. strcpy(szBuf, "thread3");
  72. }
  73. }
  74. int main()
  75. {
  76. pthread_t tid[4];
  77. if (pthread_create(&tid[0], NULL, &thread1, NULL) != 0)
  78. {
  79. _exit(1);
  80. }
  81. if (pthread_create(&tid[1], NULL, &thread2, NULL) != 0)
  82. {
  83. _exit(1);
  84. }
  85. if (pthread_create(&tid[2], NULL, &thread3, NULL) != 0)
  86. {
  87. _exit(1);
  88. }
  89. if (pthread_create(&tid[3], NULL, &thread4, NULL) != 0)
  90. {
  91. _exit(1);
  92. }
  93. sleep(5);
  94. //pthread_cancel(tid[0]);
  95. pthread_join(tid[0], NULL);
  96. pthread_join(tid[1], NULL);
  97. pthread_join(tid[2], NULL);
  98. pthread_join(tid[3], NULL);
  99. pthread_mutex_destroy(&mutex1);
  100. pthread_mutex_destroy(&mutex2);
  101. pthread_mutex_destroy(&mutex3);
  102. pthread_mutex_destroy(&mutex4);
  103. return 0;
  104. }
复制代码

清单 2. 编译测试程序

  1. [dyu@xilinuxbldsrv purify]$ g++ -g lock.cpp -o lock -lpthread
复制代码

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

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

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

  1. [dyu@xilinuxbldsrv purify]$ pstack 6721
  2. Thread 5 (Thread 0x41e37940 (LWP 6722)):
  3. #0 0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  4. #1 0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  5. #2 0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  6. #3 0x0000000000400a9b in func1() ()
  7. #4 0x0000000000400ad7 in thread1(void*) ()
  8. #5 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  9. #6 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  10. Thread 4 (Thread 0x42838940 (LWP 6723)):
  11. #0 0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  12. #1 0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  13. #2 0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  14. #3 0x0000000000400a17 in func2() ()
  15. #4 0x0000000000400a53 in thread2(void*) ()
  16. #5 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  17. #6 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  18. Thread 3 (Thread 0x43239940 (LWP 6724)):
  19. #0 0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6
  20. #1 0x0000003d19c9a364 in sleep () from /lib64/libc.so.6
  21. #2 0x00000000004009bc in thread3(void*) ()
  22. #3 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  23. #4 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  24. Thread 2 (Thread 0x43c3a940 (LWP 6725)):
  25. #0 0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6
  26. #1 0x0000003d19c9a364 in sleep () from /lib64/libc.so.6
  27. #2 0x0000000000400976 in thread4(void*) ()
  28. #3 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  29. #4 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  30. Thread 1 (Thread 0x2b984ecabd90 (LWP 6721)):
  31. #0 0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0
  32. #1 0x0000000000400900 in main ()
复制代码

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

  1. [dyu@xilinuxbldsrv purify]$ pstack 6721
  2. Thread 5 (Thread 0x40bd6940 (LWP 6722)):
  3. #0 0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  4. #1 0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  5. #2 0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  6. #3 0x0000000000400a87 in func1() ()
  7. #4 0x0000000000400ac3 in thread1(void*) ()
  8. #5 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  9. #6 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  10. Thread 4 (Thread 0x415d7940 (LWP 6723)):
  11. #0 0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  12. #1 0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  13. #2 0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  14. #3 0x0000000000400a03 in func2() ()
  15. #4 0x0000000000400a3f in thread2(void*) ()
  16. #5 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  17. #6 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  18. Thread 3 (Thread 0x41fd8940 (LWP 6724)):
  19. #0 0x0000003d19c7aec2 in memset () from /lib64/libc.so.6
  20. #1 0x00000000004009be in thread3(void*) ()
  21. #2 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  22. #3 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  23. Thread 2 (Thread 0x429d9940 (LWP 6725)):
  24. #0 0x0000003d19c7ae0d in memset () from /lib64/libc.so.6
  25. #1 0x0000000000400982 in thread4(void*) ()
  26. #2 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  27. #3 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
  28. Thread 1 (Thread 0x2af906fd9d90 (LWP 6721)):
  29. #0 0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0
  30. #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 到死锁进程

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

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

  1. (gdb) thread 5
  2. [Switching to thread 5 (Thread 0x41e37940 (LWP 6722))]#0 0x0000003d1a80d4c4 in
  3. __lll_lock_wait () from /lib64/libpthread.so.0
  4. (gdb) where
  5. #0 0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0
  6. #1 0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0
  7. #2 0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0
  8. #3 0x0000000000400a9b in func1 () at lock.cpp:18
  9. #4 0x0000000000400ad7 in thread1 (arg=0x0) at lock.cpp:43
  10. #5 0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0
  11. #6 0x0000003d19cd40cd in clone () from /lib64/libc.so.6
复制代码

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

  1. (gdb) f 3
  2. #3 0x0000000000400a9b in func1 () at lock.cpp:18
  3. 18 pthread_mutex_lock(&mutex2);
  4. (gdb) thread 4
  5. [Switching to thread 4 (Thread 0x42838940 (LWP 6723))]#0 0x0000003d1a80d4c4 in
  6. __lll_lock_wait () from /lib64/libpthread.so.0
  7. (gdb) f 3
  8. #3 0x0000000000400a17 in func2 () at lock.cpp:31
  9. 31 pthread_mutex_lock(&mutex1);
  10. (gdb) p mutex1
  11. $1 = {__data = {__lock = 2, __count = 0, __owner = 6722, __nusers = 1, __kind = 0,
  12. __spins = 0, __list = {__prev = 0x0, __next = 0x0}},
  13. __size = "\002\000\000\000\000\000\000\000B\032\000\000\001", '\000'
  14. , __align = 2}
  15. (gdb) p mutex3
  16. $2 = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0,
  17. __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}},
  18. __size = '\000' , __align = 0}
  19. (gdb) p mutex2
  20. $3 = {__data = {__lock = 2, __count = 0, __owner = 6723, __nusers = 1,
  21. __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}},
  22. __size = "\002\000\000\000\000\000\000\000C\032\000\000\001", '\000'
  23. , __align = 2}
  24. (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 平台下分析死锁题目 的方法,对一些死锁题目 的分析有肯定 作用。渴望 对大家有帮助。明确 了死锁的缘故原由 ,尤其是产存亡 锁的四个必要条件,就可以最大大概 地避免、防备 和排除 死锁。以是 ,在体系 计划 、进程 调度等方面留意 怎样 不让这四个必要条件成立,怎样 确定资源的合理分配算法,避免进程 永世 占据体系 资源。此外,也要防止进程 在处于等待状态的环境 下占用资源 , 在体系 运行过程中,对进程 发出的每一个体系 可以或许 满足 的资源申请举行 动态检查,并根据检查结果 决定是否分配资源,若分配后体系 大概 发存亡 锁,则不予分配,否则予以分配。因此,对资源的分配要给予合理的规划,利用 有序资源分配法和银行家算法等是避免死锁的有效 方法。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

avatar 上是中国十七地 | 2021-9-18 02:36:57 | 显示全部楼层
今天皮痒了?
回复

使用道具 举报

avatar 想做的都做了吗 | 2021-9-19 14:21:54 | 显示全部楼层
每天顶顶贴,一身轻松啊!
回复

使用道具 举报

avatar 小鑫鑫鑫h | 2021-9-20 12:21:42 | 显示全部楼层
在这个版块混了这么久了,第一次看见这么给你的帖子!
回复

使用道具 举报

avatar 方方圆圆272 | 2021-9-23 02:24:55 | 显示全部楼层
最近压力山大啊!
回复

使用道具 举报

avatar 心灰意冷437 | 2021-9-23 02:24:59 | 显示全部楼层
谢谢admin楼主的分享!
回复

使用道具 举报

avatar 陈陈430 | 2021-10-7 00:08:51 | 显示全部楼层
青春不在了,青春痘还在!
回复

使用道具 举报

avatar 紫色爱玫瑰咎 | 2021-10-8 16:47:22 | 显示全部楼层
admin楼主就是我的榜样哦
回复

使用道具 举报

avatar 可怜的冯三厣 | 2021-10-10 00:17:33 | 显示全部楼层
admin楼主,我告诉你一个你不知道的的秘密,有一个牛逼的网站,影视频道的网站所有电影和连续剧都可以免费看的。访问地址:http://tv.mxswl.com
回复

使用道具 举报

avatar 汪晨霞 | 2021-10-15 20:27:41 | 显示全部楼层
admin楼主加油,看好你哦!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则