程序地带

第十章 同步互斥


第十章 同步互斥
10.1 背景
多个进程一起执行有很多好处,但执行时容易产生资源共享的问题

在这里插入图片描述


进程并发执行的好处


进程需要与计算机中的其他进程和设备进行协作

好处1:共享资源

好处2:加速


I/O操作和CPU计算可以重叠(并行)程序可划分成多个模块放在多个处理器上并行执行

好处3:模块化


将大程序分解成小程序使系统易于复用和扩展

并发创建新进程时的标识分配


在这里插入图片描述


新进程分配标识中的可能错误: 在这里插入图片描述


原子操作(Atomic Operation)


原子操作是指一次不存在任何中断或失败的操作
要么操作成功完成或者操作没有执行不会出现部分执行的状态

操作系统需要利用同步机制在并发执行的同时,保证一些操作是原子操作


10.2 现实中的同步问题

在这里插入图片描述


进程的交互关系:相互感知程度


在这里插入图片描述


互斥(mutual exclusion)(一个进程占用某资源,则其他进程不能使用该资源)死锁(deadlock)(多个进程各占用部分资源,形成循环等待)饥饿(starvation)(一些进程轮流占用一个资源,导致一个进程一直无法得到该资源执行)
10.3 临界区和禁用硬件中断同步方法

在这里插入图片描述


临界区


许多物理设备都属于临界资源,还有许多变量和数据等被若干进程共享,也属于临界资源进程中访问临界资源的一段需要互斥执行的代码称为临界区访问临界资源,依次包括进入区,临界区,退出区,剩余区

进入区:


检查可否进入临界区的一段代码如可进入,设置相应“正在访问临界区”标志

退出区:


清除“正在访问临界区”标志

剩余区:


代码中的其他部分

临界区的访问规则:


空闲则入:没有进程在临界区时,任何进程可进入忙则等待:有进程在临界区时。其他进程均不能进入临界区有限等待:等待进入临界区的进程不能无限期等待让权等待(可选):不能进入临界区的进程,应释放CPU(如转换到阻塞状态)

实现进程互斥访问临界区的方法


禁用中断(硬件方法)软件方法更高级的抽象方法(硬件方法)

不同的临界区实现机制的比较:


性能:并发级别

方法1:禁用硬件中断


在这里插入图片描述 缺点:


在这里插入图片描述


10.4 方法2:基于软件的同步解决方法

在这里插入图片描述 在这里插入图片描述


方法一满足“忙则等待”,但是有时不满足“空闲则入”

第二次尝试:


在这里插入图片描述 方法二缺点:有可能同时进入临界区,不满足“忙则等待”


第三次尝试 在这里插入图片描述


方法三缺点:满足“忙则等待”,但是不满足“空闲则入”,可能两个都进不了


Peterson算法
满足线程Ti和Tj之间互斥的经典的基于软件的解决方法后写的满足条件,会循环等待,进不去,先写的进入

在这里插入图片描述


在这里插入图片描述


Dekkers算法


在这里插入图片描述


容易扩展到多线程

N线程实现方法 在这里插入图片描述


基于软件的解决方法分析


复杂


需要两个进程间的共享数据项

需要忙等待


浪费CPU时间
10.5 方法3:更高级的抽象方法

**原语:**计算机进程的控制通常由原语完成。所谓原语,一般是指由若干条指令组成的程序段,用来实现某个特定功能,在执行过程中不可被中断。在操作系统中,某些被进程调用的操作,如队列操作、对信号量的操作、检查启动外设操作等,一旦开始执行,就不能被中断,否则就会出现操作错误,造成系统混乱。所以,这些操作都要用原语来实现 原语是操作系统核心(不是由进程,而是由一组程序模块组成)的一个组成部分,并且常驻内存,通常在管态下执行。原语一旦开始执行,就要连续执行完,不允许中断 。


在这里插入图片描述


锁(lock):锁是一个抽象的数据结构。


一个二进制变量(锁定/解锁)Lock::Acquire() : 锁被释放前一直等待,返回的时候就得到锁Lock::Release(): 释放锁,唤醒任何等待的进程

在这里插入图片描述


原子操作指令: 在这里插入图片描述


交换指令: 在这里插入图片描述


自旋锁:


自旋锁是计算机科学用于多线程同步的一种锁,线程反复检查锁变量是否可用。由于线程在这一过程中保持执行,因此是一种忙等待。一旦获取了自旋锁,线程会一直保持该锁,直至显式释放自旋锁。自旋锁避免了进程上下文的调度开销,因此对于线程只会阻塞很短时间的场合是有效的。因此操作系统的实现在很多地方往往用自旋锁。Windows操作系统提供的轻型读写锁(SRW Lock)内部就用了自旋锁。显然,单核CPU不适于使用自旋锁,这里的单核CPU指的是单核单线程的CPU,因为,在同一时间只有一个线程是处在运行状态,假设运行线程A发现无法获取锁,只能等待解锁,但因为A自身不挂起,所以那个持有锁的线程B没有办法进入运行状态,只能等到操作系统分给A的时间片用完,才能有机会被调度。这种情况下使用自旋锁的代价很高。

基于TS指令来实现锁 在这里插入图片描述


线程在等待的时候消耗CPU时间

自旋锁的缺点是线程等待时消耗CPU时间。针对自旋锁的问题,出现了无忙等待锁,当锁已经被占用时,将自身线程放入等待队列,并调用调度程序。当其他线程释放锁时会将所有等待中的线程重新唤醒。


在这里插入图片描述 改进:增加一个等待队列,如果当前其他进程占用锁,将进程加入等待队列,并且进行调度,让CPU去执行别的进程,实现了让权等待。一旦切换回来,轮着这个线程了,再去查询锁的状态。


原子操作指令锁的特征:


优点:


适用于单处理器或者共享主存的多处理器中任意数量的进程同步简单并且容易证明支持多临界区

缺点:


忙等待消耗处理器时间可能导致饥饿
进程离开临界区时有多个等待进程的情况 死锁拥有临界区的低优先级进程请求访问临界区的高优先级 进程获得处理器并等待临界区(低优先级等CPU,高优先级等临界区资源)

同步方法总结: 在这里插入图片描述


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/asertgh123/article/details/112689159

随机推荐

python文件读取os.walk()

os.walk()方法用于通过在目录树中游走输出在目录中的文件名,向上或者向下。os.walk()方法是一个简单易用的文件、目录遍历器,可以帮助我们高效的处理文件、目录方面...

Mic_hu 阅读(639)

12.ruby安装(for redis)

本章专为redis集群而安装redis的番外篇。在线下载ruby安装包,比如我在/usr/src目录下安装ruby的2.3.1版本。wgethttps://cache.ruby-chin...

SexCastException 阅读(663)

剑指offer:JZ12 数值的整数次方

题目描述给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。保证base和exponent不同时为0在线链接示例1输入2,3返回值8.0000...

菜鸡的自我救赎 阅读(147)

Linux驱动:内核中的MISC“杂项”驱动

内核中的MISC“杂项”驱动1、简介2、使用方法(MISC驱动程序框架)3、使用示例3.1修改设备树添加设备节点3.2驱动程序4、测试程序1、简介  MISC是杂项英文单词...

__ASDFGH 阅读(131)

比较说明博客营销与在线百科营销有什么异同点

不同点1、信息源表现形式不同。在线百科营销内容短小精炼,重点在于系统的、严谨的新闻词或产品介绍。而博客营销以博客文章的价值为基础,并且以个人观点表述为主要模式,...

coorlor 阅读(245)

OpenCV计算机视觉编程篇一《图像编程入门》

1.1简介本文将介绍OpenCV的基本要素,并演示如何完成最基本的图像处理任务:读取、显示和存储图像。在开始之前,首先需要安装OpenCV库。安装过程非常简单...

《虚幻私塾》 阅读(378)