位置: IT常识 - 正文

在Linux平台下分析死锁问题的方法(linux必不可少的分区)

编辑:rootadmin
今天小编将为大家分享的是在Linux平台下分析死锁问题的方法!希望对大家有帮助!有需要的朋友一起去看看吧... 17-03-19

推荐整理分享在Linux平台下分析死锁问题的方法(linux必不可少的分区),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:linux用什么分区,linux能分区吗,linux分为,linux分发,linux必不可少的分区,linux分为,在linux中,在linux中,内容如对您有帮助,希望把文章链接给更多的朋友!

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

一种交叉持锁死锁的情形,此时执行程序中两个或多个线程发生永久堵塞(等待),每个线程都在等待被其它线程占用并堵塞了的资源。例如,如果线程 1 锁住了记录 A 并等待记录 B,而线程 2 锁住了记录 B 并等待记录 A,这样两个线程就发生了死锁现象。在计算机系统中 , 如果系统的资源分配策略不当,更常见的可能是程序员写的程序有错误等,则会导致进程因竞争资源不当而产生死锁的现象。

产生死锁的四个必要条件

(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 运行程序,设置能影响程序运行的参数和环境 ;

在Linux平台下分析死锁问题的方法(linux必不可少的分区)

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 ()

连续多次查看这个进程的函数调用关系堆栈进行分析:当进程吊死时,多次使用 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 平台下分析死锁问题的方法,对一些死锁问题的分析有一定作用。希望对大家有帮助。理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源 , 在系统运行过程中,对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若分配后系统可能发生死锁,则不予分配,否则予以分配。因此,对资源的分配要给予合理的规划,使用有序资源分配法和银行家算法等是避免死锁的有效方法。

本文链接地址:https://www.jiuchutong.com/zhishi/283470.html 转载请保留说明!

上一篇:ensmix32.exe进程安全吗 ensmix32进程是什么文件产生的

下一篇:RunClubSanDisk.exe是什么程序? 闪迪U盘广告推介程序

  • 单反佳能5d4(单反佳能尼康)(5d4 佳能)

    单反佳能5d4(单反佳能尼康)(5d4 佳能)

  • 手机上如何取消酷喵会员(手机上如何取消银行卡短信服务费)

    手机上如何取消酷喵会员(手机上如何取消银行卡短信服务费)

  • oppofindx5支持无线充电吗(oppofindx5支持无线)

    oppofindx5支持无线充电吗(oppofindx5支持无线)

  • word如何自动生成目录(word如何自动生成表头)

    word如何自动生成目录(word如何自动生成表头)

  • 硬盘无法格式化是什么原因(中病毒的硬盘无法格式化)

    硬盘无法格式化是什么原因(中病毒的硬盘无法格式化)

  • 微信如何看对方已闭麦(微信如何看对方是否在线)

    微信如何看对方已闭麦(微信如何看对方是否在线)

  • e5400cpu相当于i几(e5400 cpu参数怎么样)

    e5400cpu相当于i几(e5400 cpu参数怎么样)

  • freebuds3左耳电流声(freebuds3电流声能解决吗)

    freebuds3左耳电流声(freebuds3电流声能解决吗)

  • ftp是因特网中的什么东西(FTP是因特网中的什么)

    ftp是因特网中的什么东西(FTP是因特网中的什么)

  • 淘宝店可以注销吗(淘宝店可以注销吗怎么注销)

    淘宝店可以注销吗(淘宝店可以注销吗怎么注销)

  • 微信网络异常(微信网络异常封号怎么解封)

    微信网络异常(微信网络异常封号怎么解封)

  • ifunk笔记本是什么牌子(ifunk s笔记本)

    ifunk笔记本是什么牌子(ifunk s笔记本)

  • 奇遇2和2s有什么区别(奇遇2比2s贵在哪里)

    奇遇2和2s有什么区别(奇遇2比2s贵在哪里)

  • 港版note10+支持5g网络吗(港版note10支持指纹支付吗)

    港版note10+支持5g网络吗(港版note10支持指纹支付吗)

  • 快手不显示作品推广(快手不显示作品浏览记录)

    快手不显示作品推广(快手不显示作品浏览记录)

  • 微信运动间隔多久更新(微信运动多久自动刷新一次)

    微信运动间隔多久更新(微信运动多久自动刷新一次)

  • 支付宝怎么关闭运动步数(支付宝怎么关闭扣费服务)

    支付宝怎么关闭运动步数(支付宝怎么关闭扣费服务)

  • 手机杂志不更新怎么办(手机杂志app)

    手机杂志不更新怎么办(手机杂志app)

  • iphonexs长焦镜头怎么用(iphonexs长焦镜头有什么用)

    iphonexs长焦镜头怎么用(iphonexs长焦镜头有什么用)

  • 街电充电宝不见怎么挂失(街电充电宝不见了可以定位找回吗)

    街电充电宝不见怎么挂失(街电充电宝不见了可以定位找回吗)

  • 华为手机如何回到主页(华为手机如何回退系统版本)

    华为手机如何回到主页(华为手机如何回退系统版本)

  • 朋友圈限流什么意思(朋友圈有限流)

    朋友圈限流什么意思(朋友圈有限流)

  • 华为p30语音助手叫什么(华为p30语音助手唤醒不了)

    华为p30语音助手叫什么(华为p30语音助手唤醒不了)

  • 华为evr一al00是什么型号(华为evr-an00是什么机型)

    华为evr一al00是什么型号(华为evr-an00是什么机型)

  • 微信怎么弄密码锁(微信怎么弄密码图案)

    微信怎么弄密码锁(微信怎么弄密码图案)

  • 拼多多上传图片尺寸(拼多多上传图片太大怎么修改)

    拼多多上传图片尺寸(拼多多上传图片太大怎么修改)

  • package-cleanup命令   清理本地安装的RPM软件包(packet命令)

    package-cleanup命令 清理本地安装的RPM软件包(packet命令)

  • 出口退税的条件有哪些
  • 增值税税额怎么算出来
  • 会计账本需要装订的有哪些
  • 制造费用月末不可能有余额
  • 合同资产减值准备怎么计提
  • 个体户经营税收政策
  • 租赁设备出口怎么处理?
  • 个税专项扣除是什么时候开始实行
  • 托收承付和委托收款的含义和相同之处
  • 我国进口货物交税如何计算? 
  • 购买原材料已付款怎么记账
  • 车辆购置税入什么科目?
  • 建筑总包会计分录
  • 赠送的产品需要开发票吗
  • 电子税务局进项票汇总
  • 采购商品产生的费用有哪些
  • 债务利息税前列支什么意思
  • 电子税务局怎么变更财务负责人
  • 剑灵2.0win7
  • win10开机启动文件路径
  • windows为什么从7开始
  • edge浏览器总是打开新的网页
  • 电脑bios怎么设置网络启动
  • 清理系统所有垃圾
  • 外币交易犯法吗
  • 电脑开机显示屏显示无信号黑屏怎么办
  • 存货的期末计价方法是遵循哪个信息质量原则
  • 小企业会计准则调整以前年度费用分录
  • 代开发票所需的资料?
  • 详解中国女足出线形势
  • 职工薪酬纳税调整明细表案例
  • 赊销分期付款
  • 企业长期资金来源有哪些
  • 应收挂账太久有什么税务风险
  • 用php生成一个txt文件
  • 正则表达式在线生成器
  • 圣米歇尔山法语介
  • php抽奖程序源码
  • 工会经费计提分录怎么写
  • webstorm功能
  • MYSQL数据库设计与应用第二版
  • 发票清单用什么纸打印出来
  • 交物业的发票有用吗
  • 个人所得税数据怎么导入新电脑
  • 基础电信是什么
  • 研发辅助账汇总表
  • 公司出售子公司股权
  • 公司购买办公用品会计分录
  • 进项发票的作用
  • 公司如果不交社保会怎么样
  • 公益基金会的发起人是谁
  • 代开租金发票的税金怎样入账?
  • 小规模纳税人低值易耗品摊销方法
  • 营销策划费用是
  • 借资本公积贷递延所得税负债是什么意思
  • 发票必须与合同明细对应吗
  • 固定资产折旧如何进行会计处理
  • 坏账准备的会计分录例题
  • 查询公司的公积金账号怎么查
  • 快递行业的会计岗位
  • 一件产品在不同场合的价格
  • sqlserver多表查询 索引
  • 新装的ubuntu18没有网络
  • macos dock栏
  • mac系统怎么给文件夹设置密码
  • win8操作系统界面
  • 苹果Mac系统怎么切换输入法
  • Win8如何根据需要自定义文件管理器导航窗格
  • Win10控制面板在c盘哪里
  • win7 64位旗舰版设置插上耳机就能播放声音拔下耳机就自动禁音方法
  • android 自定义view onlayout
  • bc1998录制的css视频教程推荐新手看下
  • 批处理遍历文件输出文件路径
  • python如何通过键找对应值
  • jquery input
  • 纪检委是干什么工作的能管理税务管理局吗
  • 上海房屋出租交税
  • 网上交车辆购置税怎么交
  • 出口退税申报时闿
  • 强化管理定义
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设