39 死锁

server/2024/10/22 12:30:51/

目录

1.死锁
2.线程同步
3.条件变量
4.案例

死锁

概念

死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所占用不会释放的资源而处于的一种永久等待状态

四个必要条件

互斥条件:一个资源每次只能被一个执行流使用
请求与保持:一个执行流因请求资源而阻塞时,对已获得资源保持不放
不剥夺条件:一个执行流已获得的资源,在未使用完之前,不能强行剥夺
循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系,a的执行需要申请b的不释放资源,b的执行需要a的不释放资源

避免死锁

破坏死锁的四个必要条件。第一个互斥条件需要重写逻辑结构,比较困难。二和三都有对应的函数,请求与保持在加锁的时候是阻塞等待,有一个函数加锁是非阻塞等待的
加锁顺序一致
避免锁未释放的场景
资源一次性分配。资源不要分好几次给,一次性给完。就等减少死锁的可能

算法

避免死锁算法
银行家算法

线程同步

概念

上一节的买票程序,会出现只有一个线程经常抢到票。根本原因是线程对锁的竞争能力不同,拥有锁的线程在使用完后又会立即拿到锁,重新买票,导致其他线程都阻塞在加锁函数里。
这种情况的解决办法就是让阻塞的线程都排好队,新到的线程排到队列的最后面,按顺序获得锁。拥有锁的线程在使用完后不要立马去申请,而是自动排到队列最后面

同步:保证数据安全的情况下,让线程访问资源具有一定的顺序性

保证同步的一种方法就是条件变量

条件变量

概念

当一个线程互斥的访问某个变量时,它可能发现在其他线程改变状态前,神恶魔也做不了
例如一个线程访问队列时,发现队列为空,只能等待,直到其他线程将一个节点添加到队列中,这种情况就需要用到条件变量
在这里插入图片描述

当线程申请锁失败就到这个队列里排着,这样队列里就有一堆按顺序排的线程,新的线程也按这个过程。当拥有锁的线程使用完归还锁后,先敲一下铃铛,然后排到队列最后。铃铛被敲后唤醒队列中的线程申请使用锁。这个铃铛这部分就是条件变量。根据上面情形,条件变量必须依赖于锁的使用。os对这两个锁和条件变量结构也需要维护

为什么需要互斥量

条件等待是线程间同步的一种手段,如果只有一个线程,条件不满足,一直等下去都不会满足,所以必须要有一个线程通过某些操作,改变共享变量,使原先不满足的条件变得满足,并且友好的通知等待在条件变量上的线程
条件不会无缘无故的突然满足,必然牵扯到共享数据的变化。所以一定要用互斥锁来保护,没有互斥锁就无法安全的获取和修改共享数据

在这里插入图片描述
由于解锁和等待不是原子的,调用解锁之后,wait之前,如果已经有其他线程获取到互斥量,掘弃条件满足,发送了信号,那么wait将错过这个信号,可能导致线程永远阻塞在wait,所以解锁和等待必须是原子操作

wait进入函数后,回去查看条件变量等于0吗,等于就把互斥量变为1,直到wait返回,把条件变量改为1,把互斥量恢复为原样

条件变量使用规范

等待条件代码

pthread_mutex_lock(&mutex);
while (条件为假)
pthread_cond_wait(cond, mutex);
修改条件
pthread_mutex_unlock(&mutex);

给条件发送信号代码

pthread_mutex_lock(&mutex);
设置条件为真
pthread_cond_signal(cond);
pthread_mutex_unlock(&mutex);

同步概念和竞态条件

同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫同步
竞态条件:因为时序问题,导致程序异常,称之为竞态条件

条件变量初始化

int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
参数:
cond:要初始化的条件变量
attr:NULL

在这里插入图片描述

销毁

int pthread_cond_destroy(pthread_cond_t *cond)

等待条件满足

int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
参数:
cond:要在这个条件变量上等待
mutex:互斥量,后面详细解释

唤醒

int pthread_cond_broadcast(pthread_cond_t *cond); //全部
int pthread_cond_signal(pthread_cond_t *cond); //一个

条件变量和锁的使用类似,都可以局部和全局定义,全局则不需要初始化和销毁

案例

五个线程对cnt变量加加,用锁和条件变量保证线程安全和顺序性

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>int cnt = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void *count(void *num)
{uint64_t i = (uint64_t)num;while (true){pthread_mutex_lock(&lock);pthread_cond_wait(&cond, &lock);printf("线程 %d cnt:%d\n", i, cnt++);pthread_mutex_unlock(&lock);}
}int main()
{//64位整形,强转指针for (uint64_t i = 0; i < 5; i++){pthread_t tid;//不能取i的地址传入,线程里访问的和这里的i会是同一个变量,//一个修改,另一个读取错误pthread_create(&tid, nullptr, count, (void*)i);//usleep(13);}sleep(3);while (true){//pthread_cond_signal(&cond);pthread_cond_broadcast(&cond);printf("唤醒\n");sleep(1);}return 0;
}

在这里插入图片描述

我们怎么知道一个线程需要休眠?一定是临界资源不就绪时,临界资源也是有状态的,而临界资源有没有就绪时判断出来的。判断也是访问临界资源的过程,所以注定了休眠时在加锁和解锁之间。条件变量的等待函数会自动释放锁,所以必须在申请和释放锁中间


http://www.ppmy.cn/server/30827.html

相关文章

TiDB中的PD--元数据管理和调度中心

目录 PD 架构etcd 的使用TiDB 的 PD(Placement Driver)组件是整个分布式数据库系统的关键部分, 是整个集群的元数据管理和调度中心,负责存储集群的元数据和进行 Region 调度。 主要包括: 元数据存储:PD 存储了整个 TiDB 集群的元数据,包括 TiKV 集群的拓扑结构、Namespa…

240503-关于Unity的二三事

240503-关于Unity的二三事 1 常用快捷键 快捷键描述CtrlP播放/停止Ctrl1打开Scene窗口Ctrl2打开Game窗口Ctrl3打开Inspect窗口Ctrl4打开Hierarchy窗口Ctrl5打开Project窗口Ctrl6打开Animation窗口 2 关联VisualStudio2022 3 节约时间&#xff1a;将最新声明的参数移动到最上…

在STM32上实现嵌入式人工智能应用

引言 随着微控制器的计算能力不断增强&#xff0c;人工智能&#xff08;AI&#xff09;开始在嵌入式系统中扮演越来越重要的角色。STM32微控制器由于其高性能和低功耗的特性&#xff0c;非常适合部署轻量级AI模型。 本文将探讨如何在STM32平台上实现深度学习应用&#xff0c;…

在 Web3 方向有哪些工作,需要掌握哪些知识呢?

作者&#xff1a;0xrayyu 在Web3方向工作需要掌握的知识 投身Web3行业&#xff0c;无论您选择何种岗位&#xff0c;都需要构建一套涵盖基础理论、核心技术、生态应用与前沿趋势的知识体系。本文将对Web3工作者所需的整体知识进行阐述&#xff0c;并针对不同岗位的专业技能进行…

k8s环境部署gpu以及CUDA兼容性分析

本文记录和学习在实用gpu搭建k8s支持上层应用时的功能实践和遇到的问题。 1. 基础概念 CUDA本质上就是NVIDIA专为通用高性能并行计算设计的一套计算平台和编程模型&#xff0c;换句话使用GPU并行编程的规范方法&#xff0c;所以CUDA在软件层面包含了众多库&#xff0c; 那这里…

js APIS part2

什么是事件&#xff1f; 事件是在编程时系统内发生的 动作 或者发生的事情。比如用户在网页上 单击 一个按钮 什么是事件监听&#xff1f; 就是让程序检测是否有事件产生&#xff0c;一旦有事件触发&#xff0c;就立即调用一个函数做出响应&#xff0c;也称为 绑定事件或者注册…

border 是渐变色怎么设置 圆角 radius?

什么&#xff1f;渐变色的 border 无法设置 radius&#xff1f; 你5年开发了。ui 能做出的东西&#xff0c;你说你做不出来&#xff1f; .box {width: 100px;height: 150px;position: relative;z-index: 1;&::after {content: "";position: absolute;inset: 0;…

UDP_INTRODUCTION_03:介绍 - 挂起的监听调用

测试目的&#xff1a; 验证当数据报到达一个没有挂起监听&#xff08;LISTEN&#xff09;调用的UDP端口时&#xff0c;UDP是否应该发送ICMP端口不可达&#xff08;Port Unreachable&#xff09;消息。 描述&#xff1a; 本测试用例旨在确保当数据报发送到DUT上一个未被监听的…