返回顶部
首页 > 资讯 > 操作系统 >Linux上怎么做死锁
  • 432
分享到

Linux上怎么做死锁

2023-06-16 14:06:11 432人浏览 薄情痞子
摘要

本篇内容主要讲解“linux上怎么做死锁”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Linux上怎么做死锁”吧!简介死锁 (deallocks):  是指两个或两个以上的进程(线程)

本篇内容主要讲解“linux上怎么做死”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Linux上怎么做死锁”吧!

简介

死锁 (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. 测试程序

#include <unistd.h>  #include <pthread.h>  #include <string.h>   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 &ndash;进程号)的输出结果

[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 &ndash;进程号)的输出结果

[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'  <repeats 26 times>, __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' <repeats 39 times>, __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'  <repeats 26 times>, __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/284043.html(转载时请注明来源链接)

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

猜你喜欢
  • Linux上怎么做死锁
    本篇内容主要讲解“Linux上怎么做死锁”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Linux上怎么做死锁”吧!简介死锁 (deallocks):  是指两个或两个以上的进程(线程)...
    99+
    2023-06-16
  • Linux中自旋锁Spinlock怎么把Ubuntu弄死锁
    这篇文章给大家分享的是有关Linux中自旋锁Spinlock怎么把Ubuntu弄死锁的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。背景由于在多处理器环境中某些资源的有限性,有时需要互斥访问(mutual &nbs...
    99+
    2023-06-15
  • Linux死锁实例分析
    这篇“Linux死锁实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Linux死锁实例分析”文章吧。死锁简介进程(线程...
    99+
    2023-06-28
  • mysql怎么防止死锁
    这篇文章主要介绍“mysql怎么防止死锁”,在日常操作中,相信很多人在mysql怎么防止死锁问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”mysql怎么防止死锁”的疑惑有所帮...
    99+
    2024-04-02
  • 怎么避免java死锁
    这篇文章主要介绍“怎么避免java死锁”,在日常操作中,相信很多人在怎么避免java死锁问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么避免java死锁”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!来到...
    99+
    2023-06-16
  • mysql死锁怎么复现
    死锁是指多个进程互相等待而无法执行的情况。在 mysql 中,死锁通常发生在更新同一行或多行数据时。复现死锁的步骤:创建数据表并插入数据。开启两个事务并设置锁。尝试更新同一行。提交事务。...
    99+
    2024-05-30
    mysql
  • oracle死锁怎么解除
    oracle死锁解除方法:中断或终止其中一个死锁会话;回滚或提交其中一个死锁事务;监视会话并识别死锁;调整会话设置,增加超时时间;启用死锁检测器,自动检测和解除死锁。预防措施:始终以相同...
    99+
    2024-05-21
    oracle
  • oracle死锁怎么解决
    若出现 oracle 死锁,可采取以下解决方法:预防死锁:按顺序获取资源、设置超时、死锁检测。检测死锁:使用等待图表或死锁监控工具。解决死锁:回滚事务、杀死会话、优化查询、调整锁粒度。防...
    99+
    2024-05-21
    oracle
  • SQLServer中怎么实现死锁
    这篇文章将为大家详细讲解有关SQLServer中怎么实现死锁,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。  SQLServer怎么死锁  压力测试的业务场...
    99+
    2024-04-02
  • 死锁是怎么产生的
    这篇文章主要讲解了“死锁是怎么产生的”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“死锁是怎么产生的”吧!Part1 问题由于innodb engine st...
    99+
    2024-04-02
  • MySQL中怎么排查死锁
    这篇文章将为大家详细讲解有关MySQL中怎么排查死锁,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。死锁起因先介绍一下数据库和表情况,因为涉及到公司内部真是的...
    99+
    2024-04-02
  • MySQL中怎么实现死锁
    这篇文章将为大家详细讲解有关MySQL中怎么实现死锁,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1.了解锁等待与死锁出现锁等待或死锁的原因是访问数据库需要...
    99+
    2024-04-02
  • 怎么用Python模拟死锁
    这篇“怎么用Python模拟死锁”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么用Pyt...
    99+
    2024-04-02
  • Visual Studio怎么实现死锁
    这篇文章主要介绍“Visual Studio怎么实现死锁”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Visual Studio怎么实现死锁”文章能帮助大家解决问题。首先要承认这个标题有那么一丁点标...
    99+
    2023-06-17
  • mysql中怎么解除死锁
    这篇文章主要介绍了mysql中怎么解除死锁,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1、第一种:查询是否锁表show OPEN TABLES ...
    99+
    2023-06-15
  • Java中怎么排查死锁
    这期内容当中小编将会给大家带来有关Java中怎么排查死锁,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。首先,我们构造一个死锁场景。如何构造一个死锁呢很简单,只要让线程1占有对象a的锁后,再去请求对象b的锁...
    99+
    2023-06-15
  • MySQL什么情况下会死锁,发生了死锁怎么处理呢?
    🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。 🏆数年电商行业从业...
    99+
    2023-09-22
    mysql 数据库 死锁 innodb 数据库事物 原力计划
  • linux中产生死锁的原因是什么
    这篇“linux中产生死锁的原因是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“linux中产生死锁的原因是什么”文章吧...
    99+
    2023-06-29
  • sql死锁问题怎么解决
    本篇内容介绍了“sql死锁问题怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! --查询锁表信息,...
    99+
    2024-04-02
  • MySQL是怎么处理死锁的
    小编给大家分享一下MySQL是怎么处理死锁的,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、什么是死锁官方定义如下:两个事务都持有对方需要的锁,并且在等待对方释放,并且双方都不会释放自己...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作