IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 清华向勇《操作系统》学习笔记9:同步互斥 -> 正文阅读

[系统运维]清华向勇《操作系统》学习笔记9:同步互斥

9 同步互斥

9.1 背景、问题和基本概念

对于独立程序

  • 不和其他程序共享资源
  • 输入状态决定结果,具有确定性
  • 可重现起始条件
  • 调度顺序不重要

但对于并发进程来说,多个进程间有资源共享,可能会因为不同顺序出现相互的干扰。从而

  • 产生不确定性
  • 不可重现
  • 未定义行为,程序错误是间歇性发生的

实际上我们又希望使用多进程并发执行,提升效率、实现协同、模块化设计等,所以我们需要使用一些方式来克服并发设计的坏处。

我们以并发创建进程时的标识分配为例,来说明并发进程带来的问题。
程序可以调用函数fork()来创建一个新的进程

  • 操作系统需要分配一个新的且唯一的标识符
  • 在内核中,这个系统调用会运行new_pid = next_pid++;
  • 两个进程并发创建时,预期结果是,两个进程的结果不同,且next_pid加两次,但我们正常假设四条赋值加一的指令是一次执行的。
  • 当进程并发时由于共享资源混用和切换可能会使上述四条分步运行(比如进程A),从而发生混乱,如下图,会导致两个新进程id相同且next_pid只加1
    在这里插入图片描述

解决上述问题的思想就是将被打断的四条命令“打包”成一个原子操作,消除上述的执行的不完整性。

原子操作(Atomic Operation)指一次不存在任何中断或者失败的操作,要么操作完成,要么没有执行,不会出现半途而废、部分执行。

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

9.2 临界区

进程的交互关系,根据相互感知程度的不同分为如下三种:

相互感知的程度交互关系进程间的影响
相互不感知独立一个进程的操作对于其他进程的结果没有影响
间接感知(双方都与第三方方交互,如共享资源 )通过共享进行协作一个进程的结果依赖于共享资源的状态
直接感知(双方直接交互,如通信)通过通信进行协作一个进程的结果依赖于从其他进程获得的信息

同步问题的解决方案主要基于间接感知的部分,其中主要会有如下三种状态:

  • 互斥(mutual exclusion):一个进程占用资源,其他进程无法使用
  • 死锁(deadlock):多个进程各占用部分资源,形成循环等待
  • 饥饿(starvation):其他进程轮流占用资源,一个进程一直得不到资源

其中最为基本的状态称为互斥,这即是一个良好的原子操作的思路。

我们将互斥资源存放的位置称为临界区,其上资源同时只允许一个进程的访问,临界区附近的代码结构通常如下:

  • 进入区:检查是否可以进入临界区的一段代码,如果可以进入,则设定“正在进入临界区”标志
  • 临界区:进程中访问临界资源的一段需要互斥执行的代码
  • 退出区:清除“正在访问临界区”标志
  • 剩余区:跟同步互斥无关的代码

临界区的访问规则如下:

  • 空闲则入:没有进程在临界区时,任何进程可以进入
  • 忙则等待:有进程在临界区时,其他进程均不能进入临界区
  • 有限等待:等待进入临界区的进程不能无限等待
  • 让权等待(可选):不需要访问临界区的进程,应当释放CPU

在具体实现过程当中,我们必须满足前三条规则。

9.3 实现方法

9.3.1 禁用中断

禁止硬件中断响应,因而对一个正在运行的不会发生上下文切换,且没有并发。

  • 硬件将中断处理延迟到中断使能之后
  • 现代计算机体系结构都提供指令来实现禁用中断

缺点:

  1. 禁用中断之后,进程无法停止
    • 整个系统都会为此停下来
    • 可能导致其他进程处于饥饿状态
  2. 临界区可能很长,无法确定中断响应时间

所以谨慎使用。

9.3.2 软件方法

设置一些全局的共享变量,来标识两个线程对互斥资源的占用情况,从而实现同步。

通常的代码结构如下:

do{
	enter section
		critical section
	exit section
	remainder section
} while (1);

我们的设计主要基于enter section和exit section。

尝试的过程主要是要实现闲则进入、忙则等待。

结合冰箱中没有面包时买面包(在本篇笔记中略去)的案例,我们的想法是既要让人知道去买了,也要知道谁已经出发买了。

前者保证有人买面包,后者保证不买重复。即前者保证闲则进入,后者保证忙则等待。

在两线程的结构中这是非常经典的Peterson算法

前者常用flags数组表示,后者用一个变量turn表示,谁后意识到则turn就是谁,标志着不需要出发。

do {
	flag[i] = true;
	turn = j;
	while (flag[j] && turn == j);
	//CRITICAL SECTION;
	flag [i] = false;
	//REMAINDER SECTION;
} while (true)

缺点

  • 复杂,需要两个进程间的共享数据项
  • 需要忙等待,浪费CPU时间

对于Peterson算法,还有更容易扩展为多个线程的Dekkers算法。

flag[0] := false; flag[1] := false; turn :=0

do {
	flag[i] = true;
	while flag[j] == true {
		if turn not = i {
			flag[i] := false
			while turn not= i {} 
			flag[i] := true
		}
	}
	//CRITICAL SECTION
	turn := j
	flag[i] = false;
	//REMAINDER SECTION
} while (true);

绝大多数的线程都会卡在里层循环。只有当前线程执行完之后释放资源,才将下一个turn轮到的线程唤醒。

N线程的Eisenberg和McGuire算法:
在这里插入图片描述
这时候就可以实现有效的轮流。但多线程、多临界区的debug会变得更加困难。

9.3.3 更高级的抽象方法

将上述的想法抽象成一个二状态的数据结构,称为锁(lock)。
它有两个主要API:

  • Lock::Acquire()
  • Lock::Release()

将相关的互斥操作封装好之后,使用锁来控制临界区访问就会变得非常简单。

使用test and value或者exchange方法都可以简单地实现Lock::Acquire()。

Lock::Acquire() {
	while (test-and-set(value));
}
Lock::Release(){
	value = 0;
}

test and value即检查当前值是否为1,如果是1,则说明占用,继续循环,如果没占用,说明当前临界区资源闲置,并将value置1。

但上述的自旋等待锁存在忙等待的问题,我们可以将等待时的循环停下来,避免CPU繁忙。

class Lock {
	int value = 0;
	WaitQueue q;
}
Lock::Acquire() {
	while (ts(value)){
		add TCB to q
		schedule() # 执行调度算法
	}
}

Lock::Release() {
	value = 0;
	remove t one thread t from q;
	wakeup(t); 
}

原子操作指令锁适用于单处理器或者共享内存的多处理器任意数量的进程。(禁用中断只能用于单处理器)
简单且容易证明其正确性。(相比于软件方法来说实现和列举正确性更加容易)
支持多临界区。

缺点:

  • 忙等待消耗处理器时间
  • 可能会导致饥饿
  • 可能会导致死锁:高优先级拥有CPU,低优先级拥有独占资源

在这里插入图片描述

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-08-07 12:29:14  更:2021-08-07 12:30:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:41:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码