返回顶部
首页 > 资讯 > 操作系统 >Linux死锁实例分析
  • 250
分享到

Linux死锁实例分析

2023-06-28 15:06:53 250人浏览 八月长安
摘要

这篇“linux死锁实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Linux死锁实例分析”文章吧。死锁简介进程(线程

这篇“linux实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Linux死锁实例分析”文章吧。

死锁简介

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

产生死锁的四个必要条件

(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. 测试程序
 #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死锁实例分析”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网操作系统频道。

--结束END--

本文标题: Linux死锁实例分析

本文链接: https://lsjlt.com/news/320236.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Linux死锁实例分析
    这篇“Linux死锁实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Linux死锁实例分析”文章吧。死锁简介进程(线程...
    99+
    2023-06-28
  • Mysql死锁排查实例分析
    这篇文章主要介绍“Mysql死锁排查实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Mysql死锁排查实例分析”文章能帮助大家解决问题。   问题初现  ...
    99+
    2024-04-02
  • MySQL死锁案例分析
    最近项目中某个模块稳定复现MySQL死锁问题,本文记录死锁的发生原因以及解决办法。 1. 预备知识 1.1 表锁和行锁 表锁 表锁是MySQL中最基本的锁策略,并且是开销最小的策略。表锁会锁定整张数据表,用户的写操作(插入/删除/更新...
    99+
    2015-02-06
    MySQL死锁案例分析
  • MySQL死锁举例分析
    这篇文章主要介绍“MySQL死锁举例分析”,在日常操作中,相信很多人在MySQL死锁举例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”MySQL死锁举例分析”的疑惑有所帮...
    99+
    2024-04-02
  • 一个mysql死锁场景实例分析
    前言 最近遇到一个mysql在RR级别下的死锁问题,感觉有点意思,研究了一下,做个记录。 涉及知识点:共享锁、排他锁、意向锁、间隙锁、插入意向锁、锁等待队列 场景 隔离级别:Repeatable-Rea...
    99+
    2024-04-02
  • INSERT语句引发的死锁实例分析
    这篇文章主要介绍“INSERT语句引发的死锁实例分析”,在日常操作中,相信很多人在INSERT语句引发的死锁实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”INSERT...
    99+
    2024-04-02
  • C#多线程死锁实例代码分析
    这篇文章主要介绍“C#多线程死锁实例代码分析”,在日常操作中,相信很多人在C#多线程死锁实例代码分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#多线程死锁实例代码分析”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-30
  • MySQL死锁分析
    本篇内容介绍了“MySQL死锁分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!RC 隔离级别很少出GAP...
    99+
    2024-04-02
  • Oracle的死锁分析
    这篇文章主要介绍“Oracle的死锁分析”,在日常操作中,相信很多人在Oracle的死锁分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Oracle的死锁分析”的疑惑有所帮...
    99+
    2024-04-02
  • java并发编程死锁定义及避免死锁案例分析
    这篇文章主要介绍“java并发编程死锁定义及避免死锁案例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“java并发编程死锁定义及避免死锁案例分析”文章能帮助大家解决问题。场景模拟分析场景一:狭路...
    99+
    2023-06-29
  • 分析SIX锁和锁分区导致的死锁
    什么是SIX锁?官方文档锁模式中说到:意向排他共享 (SIX):保护针对层次结构中某些(而并非所有)低层资源请求或获取的共享锁以及针对某些(而并非所有)低层资源请求或获取的意向排他锁。 顶级资源允许使用并发...
    99+
    2024-04-02
  • 通过Android trace文件分析死锁ANR实例过程
    对于从事Android开发的人来说,遇到ANR(Application Not Responding)是比较常见的问题。一般情况下,如果有ANR发生,系统都会在/data/an...
    99+
    2022-06-06
    anr Android
  • C++互斥量、lock_guard类模板及死锁实例分析
    这篇文章主要介绍“C++互斥量、lock_guard类模板及死锁实例分析”,在日常操作中,相信很多人在C++互斥量、lock_guard类模板及死锁实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++...
    99+
    2023-07-02
  • sql server中死锁排查的示例分析
    这篇文章主要介绍sql server中死锁排查的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!死锁的四个必要条件:互斥条件(Mutual exclusion):资源不能被共享...
    99+
    2024-04-02
  • MySQL中死锁与日志的示例分析
    这篇文章将为大家详细讲解有关MySQL中死锁与日志的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。最近线上 MySQL 接连发生了几起数据异常,都是在凌晨爆发,由...
    99+
    2024-04-02
  • Java多线程之死锁的示例分析
    小编给大家分享一下Java多线程之死锁的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!什么是死锁死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全...
    99+
    2023-05-30
    java
  • 数据库死锁分析(行锁、间隙锁)
      分享遇到过的一种间隙锁导致的死锁案例。文后有总结知识供参考   日志出现:Deadlock found when trying to get lock; try restarting transaction 导致原因:并发导致的数据库...
    99+
    2015-10-31
    数据库死锁分析(行锁 间隙锁)
  • python多线程中互斥锁与死锁的示例分析
    小编给大家分享一下python多线程中互斥锁与死锁的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、多线程间的资源竞争以下列task1(),task2()两个函数为例,分别将对全局变量num加一重复一千万次循环(...
    99+
    2023-06-29
  • Go并发编程之死锁与活锁的案例分析
    目录什么是死锁、活锁发生死锁的案例分析发生活锁的案例分析什么是死锁、活锁 什么是死锁:就是在并发程序中,两个或多个线程彼此等待对方完成操作,从而导致它们都被阻塞,并无限期地等待对方完...
    99+
    2023-05-18
    Go死锁 活锁分析 Go 死锁 活锁 Go死锁 Go活锁
  • MySQL死锁的案例分享
    本篇内容介绍了“MySQL死锁的案例分享”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!两个死锁的小例子: ...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作