当前位置: 首页 > news >正文

淄博周村学校网站建设定制wordpress文章和页面

淄博周村学校网站建设定制,wordpress文章和页面,销售网站内容设计,asp.net网站建设教程死锁的概念在多线程编程中,我们为了防止多线程竞争共享资源而导致数据错乱,都会在操作共享资源之前加上互斥锁,只有成功获得到锁的线程,才能操作共享资源,获取不到锁的线程就只能等待,直到锁被释放。那么&a…

死锁的概念

在多线程编程中,我们为了防止多线程竞争共享资源而导致数据错乱,都会在操作共享资源之前加上互斥锁,只有成功获得到锁的线程,才能操作共享资源,获取不到锁的线程就只能等待,直到锁被释放。

那么,当两个线程为了保护两个不同的共享资源而使用了两个互斥锁,那么这两个互斥锁应用不当的时候,可能会造成两个线程都在等待对方释放锁,在没有外力的作用下,这些线程会一直相互等待,就没办法继续运行,这种情况就是发生了死锁

举个例子,小林拿了小美房间的钥匙,而小林在自己的房间里,小美拿了小林房间的钥匙,而小美也在自己的房间里。如果小林要从自己的房间里出去,必须拿到小美手中的钥匙,但是小美要出去,又必须拿到小林手中的钥匙,这就形成了死锁。

死锁只有同时满足以下四个条件才会发生:

  • 互斥条件;
  • 持有并等待条件;
  • 不可剥夺条件;
  • 环路等待条件;

互斥条件

互斥条件是指多个线程不能同时使用同一个资源

比如下图,如果线程 A 已经持有的资源,不能再同时被线程 B 持有,如果线程 B 请求获取线程 A 已经占用的资源,那线程 B 只能等待,直到线程 A 释放了资源。

持有并等待条件

持有并等待条件是指,当线程 A 已经持有了资源 1,又想申请资源 2,而资源 2 已经被线程 C 持有了,所以线程 A 就会处于等待状态,但是线程 A 在等待资源 2 的同时并不会释放自己已经持有的资源 1

不可剥夺条件

不可剥夺条件是指,当线程已经持有了资源 ,在自己使用完之前不能被其他线程获取,线程 B 如果也想使用此资源,则只能在线程 A 使用完并释放后才能获取。

环路等待条件

环路等待条件指的是,在死锁发生的时候,两个线程获取资源的顺序构成了环形链

比如,线程 A 已经持有资源 2,而想请求资源 1, 线程 B 已经获取了资源 1,而想请求资源 2,这就形成资源请求等待的环形图。

注意:4个条件必须同时满足,死锁才有可能发生。

只有在前3个条件都存在的前提下,环路等待才会导致死锁。

举例说明:

  • 如果资源不是互斥的(可以共享),即使形成环路等待,也不会死锁。

  • 如果可以强制剥夺资源,也可以打破这个环。

  • 如果线程不会“持有再等”,不会占着资源不放,也不会形成环。

排查死锁

这里举例在C/C++的linux环境下

1、查找进程

方法一

使用 ps -ef | grep 程序名

  • ps 是 “Process Status”(进程状态)的缩写,用于列出当前进程。
  • -e 选项:显示所有进程(包括其他用户的进程,不局限于当前用户)。
  • -f 选项:以完整格式显示进程信息(包括进程 ID、父进程 ID、启动时间、命令路径等)。

|(管道符):将前一个命令的输出传递给后一个命令作为输入。这里就是把 ps -ef 列出的所有进程信息,传递给 grep 命令处理。

grep 程序名:从输入中筛选包含指定关键词的内容

如果想过滤掉 grep 命令自身的临时进程,可以优化命令为:

ps -ef | grep 程序名 | grep -v grep

grep -v grep-v 表示 “排除包含指定关键词的行”,即去掉包含 “grep” 的行,只保留真正的 my_program 进程。

方法二

这个查找更加简单,直接查找,使用 pidof 程序名

2、GDB连接进程

使用 gdb -p 进程号

用于指定要附着的进程 ID(PID)。

然后你会看到类似输出:

GNU gdb (GDB) ...
Attaching to process 12345
Reading symbols from ./my_program...done.
...

这说明 GDB 成功连接上了你的程序。

3、查看线程

使用 info threads,这会列出当前进程中的所有线程。

  Id   Target Id         Frame
* 1    Thread 0x7f6f50f05740 (LWP 12345)  0x00007f6f507e0b71 in __futex_abstimed_wait_common (...)2    Thread 0x7f6f506ff700 (LWP 12346)  0x00007f6f507e0b71 in __futex_abstimed_wait_common (...)3    Thread 0x7f6f4feff700 (LWP 12347)  0x00007f6f507e0b71 in __futex_abstimed_wait_common (...)
  • 每一行是一个线程;

  • Thread 0x... (LWP xxxxx) 表示线程地址和线程 ID;

  • * 表示当前 GDB 正在查看的线程(可以切换);

  • __futex_abstimed_wait_commonpthread_mutex_lock 等表示线程在等待锁,可能是死锁。

4、查看线程的调用栈

目标:找出每个线程当前执行到哪一步,有没有线程卡在 pthread_mutex_lockfutex 等函数。

方法一:查看单个线程

(gdb) thread 1        
(gdb) bt              
(gdb) thread 2        # 切换到线程 2
(gdb) bt              # 查看线程 2 的调用栈

方法二(推荐):一次性查看所有线程堆栈

thread apply all bt

会显示

Thread 1 (LWP 12345):
#0  pthread_mutex_lock (mutex=0x55555576e2a0) at ../sysdeps/nptl/pthread_mutex_lock.c:80
#1  main_thread_func () at main.cpp:15
...Thread 2 (LWP 12346):
#0  pthread_mutex_lock (mutex=0x55555576e2c0) at ...
#1  worker_thread_func () at worker.cpp:42
...Thread 3 (LWP 12347):
#0  futex_wait (...) at futex.c:...
#1  ...

5、分析

观察线程堆栈,发现:

  1. 线程 1(LWP 12345):在 main_thread_func() 中等待锁 0x55555576e2a0
  2. 线程 2(LWP 12346):在 worker_thread_func() 中等待锁 0x55555576e2c0

怀疑点:若线程 1 持有 0x55555576e2c0 且等待 0x55555576e2a0

而线程 2 持有 0x55555576e2a0 且等待 0x55555576e2c0,则形成循环等待,即死锁。

进一步诊断步骤

1. 确认锁的持有者

在 GDB 中执行以下命令,查看每个锁当前被哪个线程持有:

(gdb) p mutex_owner(0x55555576e2a0)  # 查看锁 0x55555576e2a0 的持有者
(gdb) p mutex_owner(0x55555576e2c0)  # 查看锁 0x55555576e2c0 的持有者
  • 输出示例:若显示锁 0x55555576e2a0 被线程 2 持有,而锁 0x55555576e2c0 被线程 1 持有,则可确认死锁。

避免死锁问题的发生

前面我们提到,产生死锁的四个必要条件是:互斥条件、持有并等待条件、不可剥夺条件、

环路等待条件。

那么避免死锁问题就只需要破环其中一个条件就可以,最常见的并且可行的就是使用资源有序分配法,来破环环路等待条件

资源有序分配法

线程 A 和 线程 B 获取资源的顺序要一样,当线程 A 是先尝试获取资源 A,然后尝试获取资源 B 的时候,线程 B 同样也是先尝试获取资源 A,然后尝试获取资源 B。也就是说,线程 A 和 线程 B 总是以相同的顺序申请自己想要的资源。

我们使用资源有序分配法的方式来修改前面发生死锁的代码,我们可以不改动线程 A 的代码。

我们先要清楚线程 A 获取资源的顺序,它是先获取互斥锁 A,然后获取互斥锁 B。

所以我们只需将线程 B 改成以相同顺序的获取资源,就可以打破死锁了。

总结

简单来说,死锁问题的产生是由两个或者以上线程并行执行的时候,争夺资源而互相等待造成的。

死锁只有同时满足互斥、持有并等待、不可剥夺、环路等待这四个条件的时候才会发生。

所以要避免死锁问题,就是要破坏其中一个条件即可,最常用的方法就是使用资源有序分配法来破坏环路等待条件。

http://www.dtcms.com/a/532088.html

相关文章:

  • Multitouch for mac 触控板多点手势创建
  • SIGCHLD:进程终止与僵尸进程清理的关键
  • 数据结构(10)
  • 南皮做网站的团队管理的七个要点
  • Mysql的数据备份和高可用
  • 【Kotlin】数组集合常用扩展函数
  • css新增盒子属性——尺寸调节
  • 做阿里国际网站会有成效吗上海网站建设公司招人
  • 【课堂笔记】概率论-3
  • 【硬件基础篇】:CPU如何被制造出来
  • 面向模块的综合技术之控制集优化(七)
  • 做网站广告软件网站系统设计目标
  • 使用稀疏采样方法减轻汽车雷达干扰——论文阅读
  • 阮一峰《TypeScript 教程》学习笔记——d.ts 类型声明文件
  • Spring AOP:横切关注点的优雅解决方案
  • 如何申请网站空间和注册域名鞋子软文推广300字
  • 基于AutoDL远端服务器在pycharm复现:具身智能论文pai0
  • 如何看访问网站的dns网站开发难不难
  • 数据结构·堆
  • 阮一峰《TypeScript 教程》学习笔记——类型映射
  • 需要做网站建设和推广网站地图插件
  • PyCharm 设置 Tabs and Indents
  • Spring Boot3零基础教程,生命周期监听,自定义监听器,笔记59
  • 【SpringBoot】详解Maven的操作与配置
  • 【C++】STL容器--priority_queue的使用与模拟实现
  • 【系统分析师】高分论文:论需求分析方法及应用(电子商务门户网站系统)
  • 【大模型应用开发 6.LangChain多任务应用开发】
  • 泰安最好的网站建设公司怎么通过做网站赚钱吗
  • 初识C语言15.文件操作
  • 聊聊连续、递增