39 死锁

目录

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;
}

在这里插入图片描述

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/589592.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MFC 列表控件修改实例(源码下载)

1、本程序基于前期我的博客文章《MFC下拉菜单打钩图标存取实例&#xff08;源码下载&#xff09;》 2、程序功能选中列表控件某一项&#xff0c;修改这一项的按钮由禁止变为可用&#xff0c;双击这个按钮弹出对话框可对这一项的记录数据进行修改&#xff0c;点击确定保存修改数…

SpirngBoot整合快递100

目录 一、注册快递100 二、技术文档地址 三、需要认证的key和comcumer 四、spring boot 整合快递 100使用 4.1 引入快递100和hutool的依赖 4.2 将key和comcumer写入application.properties文件中 4.3 新建一个modle,用于将查出来的json数据转成对象 4.4 新建一个controll…

golang 基础知识细节回顾

之前学习golang的速度过于快&#xff0c;部分内容有点囫囵吞枣的感觉&#xff0c;写gorm过程中有很多违反我常识的地方&#xff0c;我通过复习去修正了我之前认知错误和遗漏的地方。 itoa itoa自增的作用在编辑error code时候作用很大&#xff0c;之前编辑springboot的error c…

python从0开始学习

目录 前言 1、print函数 2、input函数 3、保留字和标识符 总结 前言 本篇文章我们开辟一个新的学习模块&#xff1a;python。python是一个十分简洁实用的编程语言&#xff0c;我们将从0开始学习python 1、print函数 print(*args, sep , end\n, fileNone, flushFalse) pytho…

2024五一数学建模C题煤矿深部开采冲击地压危险预测原创论文分享

大家好&#xff0c;从昨天肝到现在&#xff0c;终于完成了2024五一数学建模竞赛C题的完整论文啦。 实在精力有限&#xff0c;具体的讲解大家可以去讲解视频&#xff1a; 2024五一数学建模C题完整原创论文讲解&#xff0c;手把手保姆级教学&#xff01;_哔哩哔哩_bilibili 202…

[1678]旅游景点信息Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 旅游景点信息管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql…

在idea中连接mysql

IDE&#xff08;集成开发环境&#xff09;是一种软件应用程序&#xff0c;它为开发者提供编程语言的开发环境&#xff0c;通常集成了编码、编译、调试和运行程序的多种功能。一个好的IDE可以大幅提高开发效率&#xff0c;尤其是在进行大型项目开发时。IDE通常包括以下几个核心组…

酒水门店私域流量运营搭建执行规划方案

【干货资料持续更新&#xff0c;以防走丢】 酒水门店私域流量运营搭建执行规划方案 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 PPT可编辑&#xff08;完整资料包含以下内容&#xff09; 目录 精酿啤酒品牌私域执行运营的内容策划&#xff0c;涉及以下几个…

在做题中学习(48):朴素的二分查找

. - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a; 暴力求解 for循环中&#xff0c;从nums[0]枚举到nums[n-1]&#xff0c;依次判断&#xff0c;返回 target的值。 时间复杂度 : O(N) :因为要遍历一遍数组 解法二&#xff1a;二分查找 因为此数组为有序的…

利用Github发现优质的学习项目网址

1. 直接搜索&#xff0c;star的数量越多的项目质量越高 2.Github Trending 地址: https://github.com/trending 3. Gitstar Ranking 地址: https://gistar-ranking.com/ 4. Awesome Topic 地址: https://github.com/topics/awesome

FIFO Generate IP核使用——Data Counts页详解

在Vivado IDE中&#xff0c;当看到一个用于设置数据计数选项的选项卡时&#xff0c;需要注意的是&#xff0c;尽管某些选项值可能因为当前的配置而显示为灰色&#xff08;即不可选或已禁用&#xff09;&#xff0c;但IDE中显示的有效范围值实际上是你可以选择的真实值。即使某些…

静态库、动态库回顾

回顾一下库相关的知识点&#xff0c;总结备忘一下。在某种情况下&#xff0c;你有了如下的代码&#xff0c;结构如下 //pra.h #include <stdio.h> void test_01(); //pra.c #include "pra.h" void test_01() {printf("xxxxxxx----->%s %s()\n",…

莫比乌斯变换的数学原理

一、说明 关于莫比乌斯变换&#xff0c;是一个代数几何变换的重要概念。也是双曲几何的重要理论&#xff0c;比如庞加莱盘就是建立在这个理论上&#xff0c;那么这个变换到底有哪些内容&#xff1f;本文将做出详细的解读。 二、线性变换和逆变换 在本节中&#xff0c;我们研…

# notepad++ 编辑器英文版,如何打开自动换行

notepad 编辑器英文版&#xff0c;如何打开自动换行 在Notepad中&#xff0c;如果你想要开启自动换行功能&#xff0c;可以按照以下步骤操作&#xff1a; 1、打开 Notepad 编辑器。 1.1. 依次点击菜单栏中的【视图】&#xff0c;英文版对应【View】。1.2. 在【视图】下拉菜单…

css---浮动知识点精炼汇总

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 浮动简单理解与介绍 这是我们普通的页面标签效果。 每个标签从上到下依次排列。 浮动顾名思义就是让这个标签飞翔起来。 他飞起来后&#xff0c;后面的标签来到他的位置上。 而浮动的标签就会显示在标签的上面。…

【译】Celery文档1:First Steps with Celery——安装和配置Celery

https://docs.celeryq.dev/en/stable/getting-started/first-steps-with-celery.html#first-steps Celery的第一步 Celery时一个自带电池的任务队列。 本教程内容&#xff1a; 安装消息传输代理(broker)安装Celery并创建第一个任务(task)启动Celery工作进程(worker)并执行任务…

2021-10-21 51单片机两位数码管显示0-99循环

缘由单片机两位数码管显示0-99循环-编程语言-CSDN问答 #include "REG52.h" #include<intrins.h> sbit K1 P3^0; sbit K2 P3^1; sbit K3 P3^2; sbit K4 P3^3; sbit bpP3^4; bit k1,wk10,wk20; unsigned char code SmZiFu[]{63,6,91,79,102,109,125,7,127,1…

Java高阶私房菜:JVM分代收集算法介绍和各垃圾收集器原理分解

目录 什么是分代收集算法 GC的分类和专业术语 什么是垃圾收集器 垃圾收集器的分类及组合 ​编辑 应关注的核心指标 Serial和ParNew收集器原理 Serial收集器 ParNew收集器 Parallel和CMS收集器原理 Parallel 收集器 CMS收集器 新一代垃圾收集器G1和ZGC G1垃圾收集器…

设计模式之MVC模式

在编程江湖闯荡多年&#xff0c;我手中打磨过的设计模式多如繁星&#xff0c;但论及经典与实用&#xff0c; MVC&#xff08;Model-View-Controller&#xff09;模式 绝对是个中翘楚&#xff01;它不仅是Web应用的骨架&#xff0c;更是软件架构的智慧结晶。今天&#xff0c;咱们…

DRF解析器源码分析

DRF解析器源码分析 1 解析器 解析请求者发来的数据&#xff08;JSON&#xff09; 使用 request.data 获取请求体中的数据。 这个 reqeust.data 的数据怎么来的呢&#xff1f;其实在drf内部是由解析器&#xff0c;根据请求者传入的数据格式 请求头来进行处理。 drf默认的解…