Linux线程同步【拿命推荐版】

news2025/1/15 6:46:46

目录

🚩引言

🚩听故事,引概念

🚩生产者消费者模型

 🚀再次理解生产消费模型

 🚀挖掘特点

 🚩条件变量

🚀条件变量常用接口

 🚀条件变量的原理


🚩引言

上一篇博客,我们集中讨论了Linux线程互斥相关的概念,但随着互斥锁的使用,也容易产生线程饥饿问题,所以我们有必要学习一下Linux线程同步相关的概念。接下来我们开始学习。

🚩听故事,引概念

假设在学校有一个VIP学霸自习室,这个自习室非常的豪华,但是只有一张桌子,一次只能允许一个人去上自习,这个自习室的钥匙就在门口放着,谁离钥匙近,谁就获得钥匙,就可以在利用这个自习室自习。有一天,同学张三为了在自习室中学习,享受那种超棒的学习环境,他早上5点就爬了起来。所以,等到他来到自习室门口时,没有人。他非常高兴的取得了钥匙,开开门,然后把门一反锁,开始自习。一转眼上午了,张三感觉肚子饿了,但他不想放弃他早起得到的机会,于是,他就把门锁上了,然后随身带着钥匙,门口的同学看着他的行为都非常的愤怒,但是又无奈,谁让人家来的早呢!不一会儿,张三吃完饭回来了,开开门,继续上自习。这家伙有闷头学了3个小时,突然肚子痛,要上厕所,他又带着钥匙上厕所。上完之后继续学习。可能学的时间太长了,不想学了,有好几次都开门准备放回钥匙,但每次都想到:下次不知道什么时候才能再次在这里上自习了。他放回钥匙之际,此时,他是离要是最近的人,对钥匙的竞争能力最强,所以他又获得了钥匙即自习室的使用权。张三的行为错了吗?他没错,但是不合理

门外的同学看见他这么干都非常生气,决定把这个情况反映给值班的老师,老师认为这样就是不太好,决定结束自习的同学要想再次获得自习室的使用权,必须要排队。

张三照常把钥匙放了回去,正当他想伸手再次取得钥匙时,旁边的老师说:"去排队去"。张三无奈的去排队去了。心想:“卧槽,失算了,之前不是这样的规则呀”。


听完这个故事,有些问题我们来思考这样几个问题:

  1. 按照之前的规则,张三同学反复申请这间自习室的使用权,是建立这间自习室的初衷吗?不是。那对其他同学公平吗?不公平,有的同学可能在门口等了一天,都没有使用到这间自习室。
  2. 这间自习室的钥匙就像是一把互斥锁,自习室就像是临界资源,申请这间自习室的使用权的同学就像是不同的执行流。所以,也会发生有的执行流因为竞争能力太强,就像这个同学张三,总是可以获得这把锁,然后进行访问。但是这样就会造成其他的执行流因为竞争不到对应的锁,而处于线程饥饿状态。这种状态是不利于充分利用资源的。在我们之前的抢票的代码中,我们也发现总是那一个执行流在抢票,所以这个问题要解决。而解决方案就是Linux线程同步就是让执行流按照一定的顺序(不一定是绝对的顺序)来获得访问相关临界资源的权利。

🚩生产者消费者模型

 在现实生活中,我们学生就是典型的消费者,而生产者就是工厂。

假设,有一天我想吃火腿肠了,我就跑到一个加工火腿肠的工厂,对那里的工作人员说:“给我加工火腿肠,多少钱,我给你”。工作人员听了我说的话,一定以为我是个傻子。这是因为制作火腿肠需要机器,而打开机器需要成本的,一根火腿肠指定是远远不够的,今天我来了,买了一根火腿肠,给我现场加工了,明天别人来了,又只要一根。我相信这个工厂早晚得倒闭。

所以,在生产者和消费者之间,一定还存在超市这样一个交易场所。超市的作用是集中需求,分发产品,是对生产者生产的商品的临时保存。超市存在的另一个原因是:工厂一般远离消费者,超市的存在可以更加方便消费者消费。

消费者消费吃火腿肠的同时,生产者可能在放假;生产者在生产火腿肠的同时,消费者可能又没有在吃火腿肠。这种行为用计算机术语来形容就是:生产者和消费者实现了解耦。解耦就是互相不干扰的意思。超市在计算机体系中就是共享资源--->消费者需要通过访问超市来获取商品,生产者需要通过访问超市来销售商品。在超市中类似超市这样的作用的区域我们称之为缓冲区。

我们刚刚说:生产者消费者模型实现了生产和消费的解耦。那在我们写代码的过程中,有没有强耦合的代码呢?有的。

最显著的例子就是函数调用。我们认为的函数的过程一般是这个样子的:首先实参通过形参传递给函数,然后经过函数体内部复杂的运算,输出运输的结果。

  • 调用方:生产了数据。
  • 形参变量:暂时保存数据。‘
  • 目标函数:消费了数据。

假如,我们代码中main函数中调用的func函数。我们把数据传给func函数的时候,main函数在做什么?它什么都做不了,只能等待调用func函数结束。这就是强耦合关系的例子。 


 🚀再次理解生产消费模型

我们依旧使用上面的超市的模型来深度挖掘生产消费模型的特点。生产者对应一个或者多个线程。消费者对应一个或者多个线程。

①生产者和生产者之间是什么关系?

这个大家都知道,一定是互斥即竞争关系。俗话说同行是冤家,在超市展柜上展出自己的商品时,只能同一个品牌上完货,然后另一个火腿肠品牌再上货。负责生产数据的线程之间的关系也是如此。

②消费和消费者之间是什么关系呢?

试想一下:假如过几天就是世界末日,你和同学两个人去超市买火腿肠,但是火腿肠只有一根了,你们两个肯定因为这根火腿肠而吵起来。所以消费者和消费者之间同样是互斥关系

③生产者和消费者之间是什么关系呢?

假如有一次,你去超市买火腿肠,同时超市的工作人员或者火腿肠的厂家正在上货。你们两个此时比较尴尬,是先上货呢?还是先让我拿呢?是可以沟通的。但是对于计算机而言却不是这样的,操作系统内的线程确实无法沟通的。假如在操作系统内有一块空间,一个线程正在读取这块空间中的内容,与此同时,一个线程正在修改这块空间里的内容,毫无疑问读取的内容一定发生了改变。这是不合理的,所以生产者和消费者之间首先要保持着互斥的关系,不让其同时访问

假如有这么一个节日,节日期间流行吃火腿肠,所以超市里的供不应求。张三同学为了吃上火腿肠,每天准时准点来到超市问工作人员火腿肠到了没有,假如每天会有很多人前来询问,这对这位工作人员来说,也是一种负担。所以这位工作人员就要求加张三的维信,有火腿肠了就通知张三,这样张三就不用每天来到这里询问了。假如有这样一段时间,是火腿肠的淡季,超市里堆积了大量的火腿肠,但是工厂还源源不断的生产着,所以厂家每天来超市询问是否要进货。这也让超市的工作人员非常讨厌。一天,这位工作人员也加上了厂家的微信,如果需要进货,就给厂家发消息。所以这样,就间接维护了生产者和消费者的同步关系

总结起来,生产消费模型要遵守321的原则。只要我们想写生产者消费者模型,我们的本质是要维护321原则。

3种关系

生产者和生产者要保持互斥关系②消费者和消费者之间要保持互斥关系③消费者和生产者之间既要保持互斥关系也要保持同步关系。

2种角色

生产者线程,消费者线程

1个交易场所

一段特定结构的缓冲区 

 🚀挖掘特点

①生产线程和消费线程进行解耦

②支持生产者和消费者一段时间的忙闲不均的问题

有没有可能在一段时间内,生产者的生产能力很强,但是消费者的消费水平很低;或者生产者的生产水平很弱,但是消费者的消费水平很强。但是由于中间的超市的存在,可以平衡生产者和消费者之间生产和消费的问题。在我们的计算机内部,也是如此的

③提高效率

在社会发展中,出现了超市这样的事物,一定有它存在的道理和意义。假如没有超市的存在,我们需要购买商品时,就需要跑到工厂,相比于在超市中购买,肯定要浪费更多的时间。而工厂的工作人员就需要抽出人力来销售自己生产的商品,也浪费人力资源。所以生产者消费者模型的出现,可以提高我们的效率。在我们的计算机内部也是如此,同样适用。关于提高效率这块的内容,我们后边还会说明。


所以,我们现在是不是有能力将函数调用解耦呢?

是的,现在我们就可以实现函数调用解耦了。具体我们可以这样做:

我们先定义一个缓冲区,负责存储实参。我们先将要喂给调用函数作为实参的数据存储在缓冲区内,然后调用函数可以随时从缓冲区内读取数据,作为实参进行处理,然后输出结果。这样两个执行流就由串行执行变为并发执行,真正意义上实现了解耦。


但我们忽略了一个问题:生产者和消费者的关系是互斥之间的关系,就是同一时间,仅允生产线程和消费线程中的一个线程访问缓冲区(也就是临界区)。假如生产者的优先级非常高,同时缓冲区的数据已满,不允许再写入数据,但是生产线程却不断的进行查询,这样也就会导致一个线程一直访问临界资源,就会造成我们刚刚说的自习室问题。具体如图:

如上图,结合这份伪代码,大家应该可以理解。这时,我们就要提出条件变量的概念了。

 🚩条件变量

当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。这句话应该如何理解呢?

如上图,若干个线程互斥性的访问ticket这个变量,但只有剩余票数大于0时,才能完成抢票的动作,否则什么也干不了。此时如果一个线程的优先级很高,那么它就会不停的查询ticket的值,造成一定程度上的无用查询。这时我们就可以设定一个条件变量,等到ticket大于0时,通知该线程来抢票,不用一直在这里查询了。这就是条件变量的用处。

🚀条件变量常用接口

// 所有条件变量的相关函数都在该头文件下
#include <pthread.h>
// 创建一个条件变量
pthread_cond_t +变量名
// 销毁条件变量
int pthread_cond_destroy(pthread_cond_t *cond);
// 对一个条件变量进行初始化,参数:cond:要初始化的条件,attr:NULL
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
// 如果这个条件变量是静态的或者全局的,也可以这样初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// 等待条件满足,参数:cond:要在这个条件变量上等待,mutex:互斥量,后面详细解释
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
// 如下两个函数是唤醒等待
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

注意:这些函数如果有返回值,默认成功的话,返回0;失败的话,错误码被设置。

接下来,见见猪跑

#include <stdio.h>
#include <stdlib.h> 
#include <string.h>
#include <unistd.h>
#include <pthread.h>
pthread_cond_t cond;
pthread_mutex_t mutex;
void *r1(void *arg)
{
    while (1)
    {
        pthread_cond_wait(&cond, &mutex);
        printf("活动\n");
    }
}
void *r2(void *arg)
{
    while (1)
    {
        pthread_cond_signal(&cond);
        sleep(1);
    }
}
int main(void)
{
    pthread_t t1, t2;
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);
    pthread_create(&t1, NULL, r1, NULL);
    pthread_create(&t2, NULL, r2, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
}

 🚀条件变量的原理

接下来,我们讲一个故事

一到招聘季,互联网公司总是派面试官以出差的形式去全国各地招收优秀的人才。他们每到一处地方,一般都会包下一个宾馆的一层楼,作为他们的面试场所。假设他们来到了济南,然后把面试场所安排在了万达酒店。

在一间屋子里,面试官正面试着一位同学,不一会儿面完了。此时门口挤满了求职者,他们都高举着自己的简历,然后高喊:"我先来的,应该先面我"。无奈,面试官只能挑喊的声音大的先面试。等到下午,吸取了经验,面试官在门口划定了一块区域,说:“只从这里选人面试,并且排队”

 

 其中,这块区域就像条件变量。

当条件不满足时,我们线程必须去某些定义好的条件变量下等待。

说到这里,本篇内容就结束了,我们下期博客再见!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新的特性使得数据处理更加直观本教程将带你逐步了解如何使用Java Stream API

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

暑假集中备考2024年汉字小达人:来做18道历年选择题备考吧

结合最近几年的活动安排&#xff0c;预计2024年第11届汉字小达人比赛还有4个多月就启动&#xff0c;那么孩子们如何利用这段时间有条不紊地准备汉字小达人比赛呢&#xff1f; 我的建议是充分利用即将到来的暑假&#xff1a;①把小学1-5年级的语文课本上的知识点熟悉&#xff0…

[数据集][目标检测]围栏破损检测数据集VOC+YOLO格式1196张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1196 标注数量(xml文件个数)&#xff1a;1196 标注数量(txt文件个数)&#xff1a;1196 标注…

一篇就够了,为你答疑解惑:锂电池一阶模型-离线参数辨识(附代码)

锂电池一阶模型-参数离线辨识 背景模型简介数据收集1. 最大可用容量实验2. 开路电压实验3. 混合动力脉冲特性实验离线辨识对应模型对应代码总结下期预告文章字数有点多,耐心不够的谨慎点击阅读。 下期继续讲解在线参数辨识方法。 背景 最近又在开始重新梳理锂电池建模仿真与S…

Spring底层原理之bean的加载方式八 BeanDefinitionRegistryPostProcessor注解

BeanDefinitionRegistryPostProcessor注解 这种方式和第七种比较像 要实现两个方法 第一个方法是实现工厂 第二个方法叫后处理bean注册 package com.bigdata1421.bean;import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.…

wordpress企业主题和wordpress免费主题

农业畜牧养殖wordpress主题 简洁大气的农业畜牧养殖wordpress主题&#xff0c;农业农村现代化&#xff0c;离不开新农人、新技术。 https://www.jianzhanpress.com/?p3051 SEO优化wordpress主题 简洁的SEO优化wordpress主题&#xff0c;效果好不好&#xff0c;结果会告诉你…

天气网站爬虫及可视化

摘要&#xff1a;随着互联网的快速发展&#xff0c;人们对天气信息的需求也越来越高。本论文基于Python语言&#xff0c;设计并实现了一个天气网站爬虫及可视化系统。该系统通过网络爬虫技术从多个天气网站上获取实时的天气数据&#xff0c;并将数据进行清洗和存储。同时&#…

Halcon 椭圆

一 椭圆 方差的概念: 例1 两人的5次测验成绩如下&#xff1a;X&#xff1a; 50&#xff0c;100&#xff0c;100&#xff0c;60&#xff0c;50 E(X)72&#xff1b;Y&#xff1a; 73&#xff0c; 70&#xff0c; 75&#xff0c;72&#xff0c;70 E(Y)72。平均成绩相同&#xff0c…

idea 用久了代码提示变慢卡顿优化

idea 用久了代码提示变慢卡顿优化 修改虚拟机配置 修改编译构建堆内存

【proteus经典实战】16X192点阵程序

一、简介 6X192点阵程序通常用于表示高分辨率图像或文字&#xff0c;其中16X表示像素阵列的宽度&#xff0c;192表示每个像素阵列中的点阵数&#xff0c;16X192点阵程序需要一定的编程知识和技能才能编写和调试&#xff0c;同时还需要考虑硬件设备的兼容性和性能等因素。 初始…

智能交通(2)——IntelliLight智能交通灯

论文分享&#xff1a;IntelliLight | Proceedings of the 24th ACM SIGKDD International Conference on Knowledge Discovery & Data Mininghttps://dl.acm.org/doi/10.1145/3219819.3220096摘要 智能交通灯控制对于高效的交通系统至关重要。目前现有的交通信号灯大多由手…

共模和差模的基本概念

电压电流在导体或导线中传播时&#xff0c;存在两种工作形态&#xff1a;共模和差模。电子设备的信号线在进行相互通信时&#xff0c;至少会存在两根导线以形成电传输回路&#xff0c;除此之外&#xff0c;通常还存在第三个导体&#xff0c;即“参考地”。当信号正常传输时&…

JAVA学习笔记-JAVA基础语法-DAY19-File类、递归

第一章 File类 1.1 概述 java.io.File 类是文件和目录路径名的抽象表示&#xff0c;主要用于文件和目录的创建、查找和删除等操作。 1.2 构造方法 public File(String pathname) &#xff1a;通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。public File(St…

go Channel 原理 (一)

Channel 设计原理 不要通过共享内存的方式进行通信&#xff0c;而是应该通过通信的方式共享内存。 在主流编程语言中&#xff0c;多个线程传递数据的方式一般都是共享内存。 Go 可以使用共享内存加互斥锁进行通信&#xff0c;同时也提供了一种不同的并发模型&#xff0c;即通…

python课程设计作业-TCP客户端-服务端通信

说明文档 目录 小组成员分工 作品功能介绍 使用的工具和方法 设计的步骤 课程设计中遇到的问题 结论 1. 小组成员分工 本次课程设计由以下小组成员完成&#xff1a; xxx 2. 作品功能介绍 本次课程设计的作品是一个简单的基于 TCP 协议的客户端-服务端通信示例。通过这个示…

Halcon 特征检测使用

一 Region area: 面积row: 中心的行坐标column: 中心的列坐标width: 区域的宽度(平行于坐标轴)height: 区域的高度(平行于坐标轴)row1: 左上角的行坐标column1: 左上角的列坐标row2: 右下角的行坐标column2: 右下角的列坐标‘ra’; 椭圆的长半轴…

【杂说咋说】中国历史上最古老的十大建筑​,看看你都去过几个?

【杂说咋说】中国历史上最古老的十大建筑​&#xff0c;看看你都去过几个&#xff1f; 中国作为世界四大文明古国之一&#xff0c;历史文化源远流长。在几千年的历史变迁中&#xff0c;中华先祖在神州大地上留下了无数遗迹&#xff0c;其中包括很多古建筑。本期就来介绍一下中…

C语言图书管理系统控制台程序

程序示例精选 C语言图书管理系统控制台程序 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《C语言图书管理系统控制台程序》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易读…

Web支持rtmp,rtsp,flv,h265,mp4,hls,裸流,低延时全功能播放器ovplayer解决方案

Web视频&#xff0c;监控&#xff0c;直播等业务需一个方便快捷在线播放器&#xff0c;在web上支持低延时的视频直播&#xff0c;会议&#xff0c;交互已经是工作必需&#xff0c;像终端播放器有vlc之类&#xff0c;在Web上没有相关全功能的&#xff0c;业务也需要这种功能全面…

Elasticsearch环境搭建|ES单机|ES单节点模式启动|ES集群搭建|ES集群环境搭建

文章目录 版本选择单机ES安装与配置创建非root用户导入安装包安装包解压配置JDK环境变量配置single-node配置JVM参数后台启动|启动日志查看启动成功&#xff0c;访问终端访问浏览器访问 Kibana安装修改配置后台启动|启动日志查看浏览器访问 ES三节点集群搭建停止es服务域名配置…