【Linux】多线程02 --- 线程的同步互斥问题及生产消费模型

news2024/11/23 12:13:48

🍎作者:阿润菜菜
📖专栏:Linux系统编程


目录

  • 一、线程互斥
    • 1. 为什么要有共享资源临界保护?
  • 2.理解加锁
    • 2.1 认识锁,使用锁


线程同步互斥问题是指多线程程序中,如何保证共享资源的正确访问和线程间的协作。
因为线程互斥是实现线程同步的基础和前提,我们先讲解线程互斥问题。

一、线程互斥

1. 为什么要有共享资源临界保护?

在多线程中,假设我们有一个黄牛抢票的代码,其中有一份共享资源tickets,如果多个线程都在抢票也就是对这个全局变量tickets做–操作,如果我们没有对共享资源做保护(同一时间只能一个线程对资源进行访问)的话,就会存在并发访问的问题,进而导致数据不一致问题!这种情况下,票数最后会出现负数的情况。

在这里插入图片描述
那为什么会出现并发访问导致数据不一致问题呢?–

了解上面的问题需要知道线程调度的特性,实际线程在被调度时他的上下文会被加载到CPU的寄存器中,而线程在被切换的时候,线程又会带着自己的上下文被切换下去,此时要进行线程的上下文保存,以便于下次该线程被切换上来的时候能够进行上下文数据的恢复。
除此之外,像tickets- -这样的操作,对应的汇编指令其实至少有三条,1.读取数据 2.修改数据 3.写回数据,而线程函数我们知道会在每个线程的私有栈都存在一份,在上面的例子中多个线程执行同一份线程函数,所以这个线程函数就绝对会处于被重入的状态,也就绝对会被多个线程执行!今天我们假设只有一个CPU(CPU就是核心,处理器芯片会集成多个核心)在调度当前进程中的线程,那么线程是CPU调度的基本单位,所以也就会出现一个线程可能执行一半的时候被切换下去了,并且该线程的上下文被保存起来,然后CPU又去调度进程中的另一个线程。
在这里插入图片描述
当多个线程同时进入到分支判断语句,然后去阻塞等待的情况,假设tickets已经变成了1,然后其余的线程此时都被调度上来了,他们都开始执行tickets- -,- -之后不满足循环条件线程才会退出,那么如果我们创建出了4个线程,就会有3个线程在票数已经为0的情况下继续减减,所以就会出现票数为负数的情况

要解决以上的问题,我们提出的解决方案就是:加锁

在学习锁之间先搞清两个概念

临界资源是指一次仅允许一个进程或线程使用的共享资源,如文件、变量等。
临界区是指每个进程或线程中访问临界资源的那段代码,需要保证互斥和同步的执行。

临界资源和临界区的区别是:

  • 临界资源是一种系统资源,需要不同进程或线程互斥访问,而临界区则是每个进程或线程中访问临界资源的一段代码,是属于对应进程或线程的。
  • 临界资源是一种抽象的概念,表示需要保护的共享数据或设备,而临界区是一种具体的实现,表示访问临界资源的具体操作和逻辑。
  • 临界资源是一种静态的属性,表示某种资源是否可以被多个进程或线程同时使用,而临界区是一种动态的状态,表示某个进程或线程是否正在使用某种临界资源。
    在这里插入图片描述

2.理解加锁

2.1 认识锁,使用锁

如果我们想让多个执行流串行的访问临界资源,而不是并发或并行的访问临界资源,这样的线程调度方案就是互斥式的访问临界资源!(串行就是指只要一个线程开始执行这个任务,那么他就不能中断,必须得等这个线程执行完这个任务,你才能切换其他线程执行其他的任务)

加锁后线程的操作是原子性的,怎么理解?
当线程在执行一个对资源访问的操作时,要么做了这个操作,要么没有做这个操作,只要两种状态,不会出现做了一半这样的状态,我们称这样的操作是原子性的。(就比如你妈让你写作业,你要么给我把作业写完了再出去玩,要么就一个字也别写给我滚出家门,就这两种状态,不会出现你写了一半,然后你妈让你出去玩的这种情况,这样也是原子性)

我们下面讲解互斥锁

首先锁实际就是一种数据类型,这个锁就像我们平常定义出来的变量或是对象一样,只不过这个锁的类型是系统给我们封装好的一种类型,进行重定义后为pthread_mutex_t。变量或对象在生命的时候也是可以初始化的,变量初始化后,就是变量的定义,而不是声明了。变量和对象也都有自己的销毁方案,内置类型的变量销毁时,操作系统会自动回收其资源,而自定义对象销毁时,操作系统会调用其析构函数进行资源的回收。
锁同样也是如此,锁也有自己的初始化和销毁方案,如果你定义的是一把局部锁,就需要用pthread_mutex_init()和pthread_mutex_destroy()来进行初始化和销毁,如果你定义的是一把全局锁或静态所,则不需要用init初始化和destroy销毁,直接用PTHREAD_MUTEX_INITIALIZER进行初始化即可,他有自己的初始化和销毁方案,我们无须关心静态或全局锁如何销毁。

定义好锁之后,我们就可以对某一段代码进行加锁和解锁,加锁与解锁意味着,这段代码不是一般的代码,只有申请到锁,持有锁的线程才能访问这段代码,加锁和解锁之间的代码可以称为临界区,因为想要访问这段空间必须有锁才可以访问。

那我们该如何对共享资源进行加锁和解锁呢?
手册这样写的:
在这里插入图片描述

加锁的使用方法一般包括以下几个步骤:

  • 创建并初始化一个加锁原语对象,使用相应的API来分配内存并设置属性,如pthread_mutex_init用于创建并初始化一个互斥锁对象。
  • 在访问共享资源或临界区域前,对加锁原语对象进行加锁操作,使用相应的API来获取锁的所有权,如pthread_mutex_lock用于以阻塞方式获取一个互斥锁。
  • 在访问共享资源或临界区域后,对加锁原语对象进行解锁操作,使用相应的API来释放锁的所有权,如pthread_mutex_unlock用于释放一个互斥锁。
  • 在不需要使用共享资源或临界区域时,销毁加锁原语对象,使用相应的API来释放内存并清理资源,如pthread_mutex_destroy用于销毁一个互斥锁对象。

如果忘记解锁,即一个线程在获取一个锁后,没有正确地释放锁,而导致其他线程无法获取该锁。为了避免这种情况,可以使用以下方法:

  • 使用RAII技术,即将加锁和解锁操作封装在一个类中,在构造函数中加锁,在析构函数中解锁,这样可以利用对象的生命周期来自动管理锁的状态。
  • 使用异常处理机制,即在加锁和解锁操作之间使用try-catch语句来捕获可能抛出的异常,并在catch块中进行解锁操作,这样可以避免异常导致的忘记解锁。

未完待续

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

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

相关文章

阿里P8大佬七天七夜制作这份自动化核心知识点,错过了就是错过了

整理了一份自动化核心知识点。覆盖了web前端基础,HTML标签,CSS样式,自动化测试工具,webdriver环境搭建,元素定位,手机操作系统,移动自动化测试工具,自动化测试的流程与分类&#xff…

web自动化测试入门篇01——框架介绍

1. 目的 web自动化测试作为软件自动化测试领域中绕不过去的一个“香饽饽”,通常都会作为广大测试从业者的首选学习对象,相较于C/S架构的自动化来说,B/S有着其无法忽视的诸多优势,从行业发展趋、研发模式特点、测试工具支持&#x…

高完整性系统(7)Formal Verification and Validation

文章目录 Specification Process 规格化过程State Invariants案例check ... expect Alloy是一种用于构建和检查抽象模型的语言和工具。当Alloy说所有断言都成立时,这意味着你的模型或规格在给定范围内已成功通过了所有的断言检查。换句话说,对于你所定义…

SOLIDWORKS PDM 独立程序 C#

本主题介绍如何创建登录到 一个 SOLIDWORKS PDM Professional 文件库,并列出根文件夹中的文件。 启动Visual Studio.文件 > 新建 > 项目 > Visual C# > WPF(也可以使用WF) 输入程序名称选择存储路径确定在解决方案资源管理器中…

(学习日记)2023.06.06

写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈。 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录&a…

【Linux】基础文件IO、动静态库的制作和使用

基础IO 前言回顾C语言文件IO操作三个标准 系统文件I/O系统调用接口不带mode的open带mode的openwirtereadopen的第二个参数flagsopen返回值文件的管理0,1,2演示文件描述符的分配规则重定向C中的0、1、2输入重定向追加重定向 另一种重定向的方式dup2实现输…

MySQL5.7主从同步配置(一台master,两台slave)

1. 下载MySQL(5.7.42) rpm -ivh http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm2.安装 yum install mysql-server2.1 安装过程中如果报错如下,按下边方法处理。否则略过即可 2.2 解决方案:执行以下命令 rpm --import https…

mongodb redis mysql 区别

一、MySQL 关系型数据库。 在不同的引擎上有不同 的存储方式。 查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。 开源数据库的份额在不断增加,mysql的份额页在持续增长。 缺点就是在海量数据处理的时候效率会显著变慢。 二、Mo…

Vue3中setup函数、以及父子组件传值讲解

文章目录 1.vue3中setup函数的执行时机2.setup函数的两种写法2.1 普通写法2.2 语法糖写法 3.vue3父组件给子组件传值。4.vue3子组件给父组件传值 1.vue3中setup函数的执行时机 setup选项的写法和执行时机,setup函数在beforeCreate函数之前执行,并且是自…

以安全为底线 共迎机遇和挑战|2023 开放原子全球开源峰会可信基础设施技术分论坛即将启幕

蚂蚁集团的业务领域,对于「可信」有非常高的技术要求。这种可信技术不仅体现在可靠、健壮,也体现在金融领域独有的风控难题以及分布式系统中持续提供服务的续航能力。可信基础设施中有大量的开源项目,而新的机会也在不断涌现。 2023 开放原子…

echarts 图表导出PDF(带滚动条)/图片导出PDF

echarts 图表导出PDF[带滚动条]/图片导出PDF 效果展示提出问题思考问题解决问题导出PDF 里面的页头中文乱码问题参数说明 效果展示 提出问题 在开发过程中,有需求是将展示出来的echarts图表导出为pdf 原本我的滚动条是使用echarts图表进行的滚动,但通过了解后得知,echarts图表如…

《人月神话》阅读推荐

用了两周的时间,大致过了一遍。书中讲述的很多方面可能此时并没有很深刻的体会,但是该书的预见性和分析还是很让人钦佩的。书中对项目、产品、程序、程序员等一系列对象的分析是相当精准的。虽然距今已有四十多年,但很多依旧在发生。   书中…

Java设计模式(四)

系列文章目录 UML类图 文章目录 系列文章目录前言一、UML类图二、UML基本介绍三、UML图1.类图—依赖关系(Dependence)2.类图—泛化关系(generalization)3.类图—实现关系(Implementation)4.类图—关联关系(Association)5.类图—聚合关系(Aggregation)6.类图—组合关系(Composi…

分布式(二)-大型网站架构演化发展历程

大型网站架构演化发展历程 大型网站的技术挑战主要来自于庞大的用户,高并发的访问和海量的数据,任何简单的业务一旦需要处理数以 P 计的数据和面对数以亿计的用户,问题就会变得很棘手。大型网站架构主要解决这类问题。 初始阶段的网站架构 …

MinIO 分片上传

文章目录 1.MinIO 简介2.为什么要分片上传?3.实现思路4.具体实现初始化客户端获取分片上传的预签名 URL合并分片中止合并 5.FAQ端口错误协议错误 参考文献 1.MinIO 简介 MinIO 是适用于 AI 的高性能对象存储系统。 MinIO 简单易用。简单性是 EB 级数据基础设施的基…

宝塔配置MySQL队列调度 | ModStart

执行以下操作前提前进入网站根目录,如 cd /www/wwwroot/xxx.com执行 artisan 命令前请参照 开发教程 → 开发使用常见问题 → 如何运行 /www/server/php/xxx/bin/php artisan xxx 命令 ① 生成数据库队列表迁移文件 在执行该步骤前,请先检查迁移文件 da…

【CSS 05】文本颜色 文本对齐 文字装饰 文本转换 文字间距 文本阴影 字体 字体样式 字体大小 谷歌字体

CSS 说在前面文本 text文本对齐 text-align文字装饰 text-decoration文本转换 text-transform文字间距 text_spacing文本阴影 text-shadow字体 font字体样式 font-style字体大小 font-size谷歌字体简写属性 shorthand 说在前面 事实证明,Zoro只要出现在标题就会被识…

go-GUI开发:fyne解决中文乱码+注册windows服务

go-GUI框架:fyne教程及解决中文乱码等常见bug 1 fyne教程 fyne教程地址: https://www.topgoer.cn/docs/goday/goday-1crdp17nj4v6phttps://pkg.go.dev/fyne.io/fyne/v2#section-readme 1.1 介绍 简单易用,fyne提供了简单直观的API&#xff…

iOS编译提效插件cocoapods-jxedt方案详解

1. 前言 本篇文章是cocoapods-jxedt插件实现方案的详解,主要从以下几个方面阐述了一下插件的实现方案和历程。 插件文件目录介绍插件的工作流程介绍插件实现过程中的问题和解决方案记录 如果你对插件的使用还不了解,建议先读一下cocoapods-jxedt使用介…

CVE漏洞复现-CVE-2023-32233 NetFilter权限提升

CVE-2023-32233 NetFilter权限提升 Netfilter是Linux 内核中的网络数据包处理框架(iptables)通过各种规则和过滤器,基于数据包的来源、目标地址、协议类型、端口号等信息,控制网络流量和数据包的转发和处理具体,详情请…