Linux:锁和线程同步的相关概念以及生产者消费者模型

news/2024/5/26 20:08:10/文章来源:https://blog.csdn.net/qq_73899585/article/details/136626544

文章目录

  • 加锁的基本原则
  • 死锁
    • 死锁的概念
    • 死锁的条件
  • 线程同步
  • 生产者消费者模型
    • 模型的理解
  • 理解cp问题
  • 条件变量

本篇总结的是关于Linux中锁的相关概念以及生产者消费者模型

加锁的基本原则

加锁的基本原则:谁加锁谁解锁,不要把加锁和解锁这样的操作放在两个线程中

死锁

死锁的概念

下面讲述死锁的一种情况,进而对于死锁有一个较为清楚的认知:

在这里插入图片描述
上图展示的是死锁的其中一个场景,对于这个代码块来说,想要访问这部分资源必须需要两个锁,一个是lock1,一个是lock2

那此时有两个线程A和B,对于线程A来说,它现在持有一把锁lock1,对于线程B来说它持有一把锁lock2,但此时这两个线程都无法进入对应的代码块中,此时线程A要访问这块资源,发现条件不足,少一把锁,于是被挂起,线程B要访问这块资源,发现条件不足,少一把锁,于是被挂起,基于这样的原因,这两个线程在之后的每一次被调度都会被阻塞,这就是一个最基本的死锁问题

死锁的条件

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

对比上述的四个条件,再次回到刚才的这个死锁场景

  1. 互斥条件:代码中间的这部分资源只能被线程A和B当中的一个进行访问,构成了互斥条件
  2. 请求和保持:线程A和B发生阻塞的时候,不会对于当前它们所持有的锁进行释放,而是占用了现有的这个锁,直到下次被调度
  3. 不剥夺条件:线程A不能去把线程B当前所持有的锁剥夺下来供自己使用
  4. 循环等待:线程A和B交替对于锁的申请判断的逻辑构成了一个环的概念

所以,想要构成死锁,必须要满足上述的这四个条件,只要有一个不满足就不应构成死锁,因此也有了另外一个话题,想要破坏死锁,本质上来说只要破坏了这四个条件中的一个就可以了

线程同步

前面讲解了线程互斥的基本原理,那么本节主要讲解关于线程同步的原理,对于线程同步的理解,先给出下面的使用场景:

现有一个线程,拥有一把锁,所以它在以很高的强度对于这个资源进行访问,但是很不幸,处于一些原因,它的访问每次都是无效的,而由于规则的指定失误,这个线程每次都能访问到这个资源,而其他的线程却无法访问到这个资源,这样就造成了线程饥饿的现象出现,那为了解决这样的问题,就给出了线程同步的概念

线程同步是指在多线程编程中,控制多个线程之间的执行顺序和共享资源的访问,以确保数据的一致性和正确性,例如在上面的情景中,可以制定特定的规则,当前线程结束后,必须进行某个队列中进行排队,当排队结束后才能继续进行访问,这样本质上就解决了对于一份共享资源被同一个线程高强度的重复访问,就会造成所谓线程饥饿的现象出现,换句话说,线程同步就是如何合理的使用资源解决线程饥饿的问题,也可以说是让临界资源在使用安全的前提下,让多线程的执行具有一定的顺序性,这个就是所谓线程同步的基本概念

生产者消费者模型

先上定义:
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的

模型的理解

对于这个模型的理解,首先从生活的场景入手:在生活中,超市就是一个很经典的生产消费模型,每一个消费者想要获取生产者生产出来的物品,而生产者生产出来的问题要放到超市,超市再把这些内容卖给消费者,就是这样的一个过程

对于这个模型的理解来说,可以把这个生产者看成是线程,而消费者也是线程,那生产者生产的内容交给消费者,这个过程该如何理解?实际上直接把计算机中的数据当成商品就可以

生产者消费者的这个模型,本质上来说就是执行数据流动的过程,把数据由一批线程交由另外一批线程,可以看成是数据流动,也可以是理解为通信的概念,但现在我们抛开这个超市本身的问题,对于供货商来说,想要把自己的商品交到超市里面,所以超市对于供货商来讲本身就是一种临界资源,消费者要到超市中去消费,前提要保证这个过程是安全的,对应到线程的概念来说,就是一批线程要把数据交给另外一批线程,在这个交付的过程中务必要保证是线程安全的

那如何理解线程安全?下面我给出一个线程不安全的例子,比如说现在超市正在供货,但当这个货还没放到货架的时候就被消费者拿走了,那对于超市来说,它其实并不知道这个东西到底是否存放到了货架中,甚至可能在进行统计数量的时候只是统计了放置到货架上的内容,并没有统计这个用户前面拿走的这个内容,这就可以看成是一个数据不安全的问题,对应到线程中也是如此,如果产生了上述这样的类似的问题,那就可以把这个过程看成是不安全的现象

有了上述的概念,下面来理解三个关系

  1. 生产者和生产者之间的关系:竞争并且互斥,一个货架只能放一种货品,并且总量是保证的,一个供货商的东西放多了,其他供货商自然就没了,并且在一个厂商放东西的时候另外一个不能也放,这叫做互斥
  2. 消费者和消费者之间的关系:竞争并且互斥,原理和上述相似,货架总共就这么多东西,拿的多的自然就有拿的少的
  3. 生产者和消费者之间的关系:互斥并且同步,具体理解如下:

互斥性:互斥性确保在同一时间只能有一个线程(生产者或消费者)访问共享资源(缓冲区)。这意味着当一个线程正在对缓冲区进行生产或消费操作时,另一个线程不能同时进行相同的操作。这样可以避免数据竞争和数据不一致的问题。

同步性:同步性确保生产者和消费者之间的操作是协调一致的,即当生产者生产了数据并放入缓冲区后,消费者必须能够及时地从缓冲区中取出数据进行处理;反之,当缓冲区为空时,消费者必须等待生产者生产数据。同样地,当缓冲区已满时,生产者必须等待消费者消费数据

理解cp问题

CP 问题通常是指"Consumer-Producer"(消费者-生产者)问题,那下面先举一个这样的例子

假设现在有函数调用,在main函数中函数执行的很快,但是如果跳转到函数体内部,就执行的很慢,那么此时外部的这个main函数就必须要等待内部的函数调用执行结束后才能进行继续的调用,那这个过程就是普通的单线程可能会经常遇到的一个情景

那能不能设计这样的一个情景,使得这个执行快的这部分一直很快,慢的部分一直很慢,两个执行流互不干扰呢?那cp问题就可以解决这样的情景,cp问题的主要目的就是实现一个多执行流之间的执行解耦问题,线程在不断的把数据很快的输送到一个地方,而另外一批线程正在慢慢的进行数据的计算等,这个逻辑和前面的超市的逻辑一样,如果按照单线程的理解来说,供货商的生产速度很快,但是消费者消费的很慢,供货商必须等消费者消费结束后才能继续供货,这样必然会导致效率的问题,因此就有了生产消费模型,供货商快速的生产,把货放到超市里面,而消费者只需要慢慢的对这些货进行消费就可以了,把供货商和消费者之间的关系进行了一个解耦,这样就实现了想要形成的一个状态

换句话说这是一个忙闲不均的问题,生产的这一端很忙,在不停的向这段空间中扔数据,而消费的却闲,但不影响生产继续生产,这就是因为有这段空间带来的好处

条件变量

在生产消费模型中,条件变量是一个很重要的概念,再以超市为例,当货物还没有就绪的时候,消费者如果要在超市中申请货物是申请不到的,而频繁的进行申请可能还会带来影响供货的速度,那为了解决这样的问题就引入了条件变量的概念,可以把条件变量理解为一个提醒器,在货物就绪的时候就提醒消费者,可以进行消费了,这样就避免了消费者在进行频繁申请却没有成果带来的这样的弊端

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

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

相关文章

从零开始搭建医保购药APP:技术选择与开发流程

医保购药APP作为一种创新的医疗服务工具,为用户提供了便捷的医保购药流程,同时也为医疗机构提供了更高效的管理和服务方式。今天小编将为大家讲解如何从零开始搭建一款医保购药APP,包括技术选择和开发流程。 一、技术选择 在搭建医保购药APP…

【海贼王的数据航海】栈和队列

目录 1 -> 栈 1.1 -> 栈的概念及结构 1.2 -> 栈的实现 1.2.1 -> Stack.h 1.2.2 -> Stack.c 1.2.3 -> Test.c 2 -> 队列 2.1 -> 队列的概念及结构 2.2 -> 队列的实现 2.2.1 -> Queue.h 2.2.2 -> Queue.c 1 -> 栈 1.1 -> 栈的…

c++指针的定义和使用

1、定义一个指针 int a10; //定义指针的语法&#xff1a;数据类型 * 指针变量名&#xff1a;int * p&#xff1b; //让指针记录变量a的地址&#xff1a;p &a; int a 10;int* p; p &a; cout << "a的地址为&#xff1a;" << &a <<…

Flink 性能优化总结(反压优化篇)

反压的理解 Flink 中每个节点间的数据都以阻塞队列的方式传输&#xff0c;下游来不及消费导致队列被占满后&#xff0c;上游的生产也会被阻塞&#xff0c;最终导致数据源的摄入被阻塞。简单来说就是系统接收数据的速率远高于它处理数据的速率。 反压如果不能得到正确的处理&am…

mineadmin 快速安装部署(docker环境)

前提条件&#xff1a;已安装docker 一、下载dnmp环境包 github地址&#xff1a;https://github.com/tomorrow-sky/dnmp gitee地址&#xff1a; https://gitee.com/chenjianchuan/dnmp 二、看一下dnmp包目录结构 三、打开docker-compose.yml 文件&#xff0c;将不需要…

机器学习(25)文献阅读

这里写目录标题 摘要Abstract:一、论文论文思想网络架构基本块结构特征融合模块Loss Function结论 二 、GAN2.1 如何客观评价GAN的生成能力&#xff1f;2.2 Inception Score2.3 Mode Score2.4 Kernel MMD (Maximum Mean Discrepancy)2.5 Wasserstein distance2.6 1-Nearest Nei…

C++程序设计-第四/五章 函数和类和对象【期末复习|考研复习】

前言 总结整理不易&#xff0c;希望大家点赞收藏。 给大家整理了一下C程序设计中的重点概念&#xff0c;以供大家期末复习和考研复习的时候使用。 C程序设计系列文章传送门&#xff1a; 第一章 面向对象基础 第四/五章 函数和类和对象 第六/七/八章 运算符重载/包含与继承/虚函…

算法-双指针、BFS与图论-1101. 献给阿尔吉侬的花束

题目 思路 BFS可以搜环&#xff0c;有环也没有关系&#xff0c;如果有解&#xff1a;一定可以找到一条最小步数的合法的路径Python中 collections模块的详细用法介绍_python collections-CSDN博客引用自上述文章&#xff1a; append(x)&#xff1a;添加 x 到右端。appendleft(…

【机器学习】科学库使用第1篇:机器学习(常用科学计算库的使用)基础定位、目标【附代码文档】

机器学习&#xff08;科学计算库&#xff09;完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;机器学习&#xff08;常用科学计算库的使用&#xff09;基础定位、目标&#xff0c;机器学习概述&#xff0c;1.1 人工智能概述&#xff0c;1.2 人工智能发展历…

豆瓣书影音存入Notion

使用Python将图书和影视数据存放入Notion中。 &#x1f5bc;️介绍 环境 Python 3.10 &#xff08;建议 3.11 及以上&#xff09;Pycharm / Vs Code / Vs Code Studio 项目结构 │ .env │ main.py - 主函数、执行程序 │ new_book.txt - 上一次更新书籍 │ new_video.…

贝叶斯优化CNN-BiLSTM回归预测(matlab代码)

贝叶斯优化CNN-BiLSTM回归预测matlab代码 贝叶斯优化方法则采用贝叶斯思想&#xff0c;通过不断探索各种参数组合的结果&#xff0c;根据已有信息计算期望值&#xff0c;并选择期望值最大的组合作为最佳策略&#xff0c;从而在尽可能少的实验次数下达到最优解。 数据为Excel股…

双系统合集——Ubuntu+Windows 10安装融合!

平时我们常见的电脑系统都是单一 一个Windows,当然,对于日常办公或娱乐足够了,但是对于发烧友来说,这种呆板了。万一某天系统崩溃了,只能泪两行。这时双系统就体现出他的优点了,一个系统崩溃了,还可以进入另一个系统使用,而且两个系统都是完全独立的,互不影响,开机时…

LeetCode.2864. 最大二进制奇数

题目 2864. 最大二进制奇数 分析 这道题目其实我们只需要保证最后一位是1&#xff0c;其余的1都放在最前面&#xff0c;这样得到的就是最大二进制奇数。 所以&#xff0c;我们先统计给定的字符串有多少个 1&#xff0c;多少个 0&#xff0c;把其中一个 1 放在最后一位&…

excel批量数据导入时用poi将数据转化成指定实体工具类

1.实现目标 excel进行批量数据导入时&#xff0c;将批量数据转化成指定的实体集合用于数据操作&#xff0c;实现思路&#xff1a;使用注解将属性与表格中的标题进行同名绑定来赋值。 2.代码实现 2.1 目录截图如下 2.2 代码实现 package poi.constants;/*** description: 用…

【智能算法】蜻蜓算法(DA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.代码实现4.参考文献 1.背景 2016年&#xff0c;Mirjalili受到蜻蜓静态和动态集群行为启发&#xff0c;提出了蜻蜓算法(Dragonfly algorithm, DA)。 2.算法原理 2.1算法思想 蜻蜓集群有两种行为目的&#xff1a;狩猎&#xf…

Java容器

容器 一、容器的概念二、Collection接口Collection接口的常用方法List和Set接口List接口List接口的实现类List接口特有的方法小结 Iterator接口Iterator接口的方法增强For循环&#xff08;For-each&#xff09;ListIterator Set接口Set接口中的实现类HashSetComparable接口sort…

OPPO后端二面,凉了!

这篇文章的问题来源于一个读者之前分享的 OPPO 后端凉经&#xff0c;我对比较典型的一些问题进行了分类并给出了详细的参考答案。希望能对正在参加面试的朋友们能够有点帮助&#xff01; Java String 为什么是不可变的? public final class String implements java.io.Seri…

从GPT入门,到R语言基础与作图、回归模型分析、混合效应模型、多元统计分析及结构方程模型、Meta分析、随机森林模型及贝叶斯回归分析综合应用等专题及实战案例

目录 专题一 GPT及大语言模型简介及使用入门 专题二 GPT与R语言基础与作图&#xff08;ggplot2&#xff09; 专题三 GPT与R语言回归模型&#xff08;lm&glm&#xff09; 专题四 GPT与混合效应模型&#xff08;lmm&glmm&#xff09; 专题五 GPT与多元统计分析&…

Linux--vim

一.什么是vim Vim&#xff08;Vi IMproved&#xff09;是一种文本编辑器&#xff0c;通常在Linux和其他类Unix操作系统中使用。它是Vi编辑器的增强版本&#xff0c;提供了更多的功能和定制选项。Vim具有强大的文本编辑和编程功能&#xff0c;支持语法高亮、代码折叠、宏录制、…

Nodejs 第五十五章(socket.io)

传统的 HTTP 是一种单向请求-响应协议&#xff0c;客户端发送请求后&#xff0c;服务器才会响应并返回相应的数据。在传统的 HTTP 中&#xff0c;客户端需要主动发送请求才能获取服务器上的资源&#xff0c;而且每次请求都需要重新建立连接&#xff0c;这种方式在实时通信和持续…