【操作系统】理解并发

 
 

引子

几十年前,手工操作的早期计算机需要吞入打孔的纸带,人机速度矛盾使得资源利用率极低。

前人们聪明地引入了磁带+监督程序的组合,让疲于接线的“程序员”们解放了双手。可是,此时的内存中只有一道程序,资源利用率仍旧不容乐观;

紧接着,多道批处理系统出现,多道程序可以并发执行,资源利用率大大提升。至此,操作系统正式诞生

不难发现,并发其实是伴随着操作系统一同出现。操作系统这门学科的生命力,总是离不开调度二字;人们对于调度算法的执念,最初大概是起源于对于并发的思考吧。

(题外话,书上都说OS最基本的两个特征是并发共享,其实我以为OS最令人啧啧称奇的应该是并发虚拟,它们也是研究调度算法的目的)

下面,将先给出并发的定义(不用急着去背),紧接着引入进程和线程的概念(起码我们要知道究竟是谁在并发),然后就是绕不过去的调度算法(CPU如何让程序“宏观同时、微观交替”地执行),接着是最能体现并发的同步和互斥问题(也是408的重点,难受),由此引出并发进程的死锁问题(相对简单),最后将用高级语言来体验一下程序的并发执行(这里大概是Java多线程与同步化的入门知识)

>>> go

 

概念

并发的一种解释是:程序宏观同时微观交替地执行。

百度百科详细的对此进行了解释:在一个时间段内,多个程序都完成了启动-运行-完毕的动作,但是在某一时刻点上,处理机上只有一个程序在运行。

老师们总喜欢把两个汉字相近的词语放在一起,然后要求你从概念的层次比较它们的异同——比如现在要说到的:并发并行
并发:多个事件在同一时间间隔内发生,注意这些事件在宏观上同时发生,在客观上交替发生
并行:多个时间在同一时刻内发生,百度百科上将其翻译为“并排行走”
 
拘泥于汉字会让你徒增烦恼,不妨换一种语言:并发Concurrent并行Parallel
这就很容易理解了。平行线没有交点,就像并行的程序没有资源的争抢。

 

进程

传统定义:进程是一次程序的执行过程

当今定义:进程是进程实体(PCB+程序段+数据段)的运行过程

为什么要提出进程的概念?因为进程是处理机调度和资源分配的基本单位。某种意义上可以理解为,并发的基本单位。我们研究的就是进程的并发。

并发的过程中,许多个进程在马不停蹄地进行状态的转换⬇️

在这里插入图片描述

 

线程

进程之间并发执行,但一个进程的内部只能串行执行。(传统进程)

因此我们让进程再分为一个个线程,而线程之间可以并发执行——这提升了并发度

引入线程后,资源分配和调度也发生了微妙的变化:

  • 传统进程机制:进程是资源分配的基本单位,也是调度的基本单位
  • 线程机制:进程是资源分配的基本单位,(内核级)线程是调度的基本单位

注意,“并发”也与之前有些许不同:

  • 进程间的并发需要切换进程运行环境,而同一进程的线程间并发不需要切换进程运行环境
  • 为什么要强调这一点?因为这说明,切换同进程的线程,系统开销非常小!

这里提到了进程切换时系统开销的问题,这也能解释为什么“并发度越高越好”这句话是错误的。

 

调度

调度是实现并发的关键,即所谓的“微观交替”究竟如何实现。

我们知道,单处理机在同一时刻只能做一件事情,也就是说,在某一时刻,只有一个幸运儿进程可以获得CPU并执行。现在,把自己想象成管理者(即OS),你会如何在众多的争夺CPU的进程中选出那个幸运儿呢?

这就是调度算法:

  • 先来先算法(First Come First Serve):先来后到,人之常情
  • 短作业/进程优先算法(Shortest Job/Process First):谁最快,谁先来。你不会想让一个买一百个面包的人排在你的前面
  • 高响应比优先算法(Highest Response Ratio Next):响应比 = (等待时间+运行时间)/ 运行时间。下面还会再说,先伏笔

理解:FCFS只考虑了等待时间,却没有考虑运行时间;SJF只考虑了运行时间,却没有考虑等待时间;HRRN显然是对前两种思路的折中兼顾。它们似乎都是可行的,但好像它们都没有考虑响应时间、系统整体指标、以及紧急程度——这是早期批处理系统的特点。下面将介绍三种更适合交互式系统的调度算法:

  • 时间片轮转(Round-Robin):轮流地给就绪队列队头的进程分配时间片,时间片用完后,把这个进程无情地拉到队尾
  • 优先级调度算法人有高低贵贱 ,事有轻重缓急。当然是紧急的作业/进程先获得处理机
  • 多级反馈队列调度算法:上面两种算法的折中和缝合,篇幅有限不能赘述,但这真的是很妙的算法

理解:

  1. 一是理解时间片的大小对RR算法的影响。若时间片太大,甚至每个进程都能在一个时间片内完成,则RR退化为FCFS;若时间片太小,要知道进程调度和切换是有代价的,并发度不会像理想中那种越来越高,而是会不堪过重的开销而导致整个系统的效率下降。
  2. 二是理解优先级。优先级分为静态优先级和动态优先级,它们的区别是优先级是否可变。如果可变,该如何变呢?一个进程苦苦等待了太久,是不是该适当提高它的优先级呢?一个进程霸占CPU运行了太久,是不是该适当降低它的优先级呢?惊讶地发现,我们回收了一个伏笔——这正是响应比的本质!

 

互斥

试想这么一种情况:有两道程序分别打印两篇文章,但是只有一台打印机。两道程序并发执行,也就是说,它们交替着获得CPU并执行。现在一道程序控制着打印机打印了一行半,这时发生了调度,另一道程序接着开始打印自己的文章…最终,我们打印出了一篇前言不搭后语的文章 ······

这便是互斥问题——两个进程自顾自的对打印机(临界资源)进行访问。

我们从软件和硬件两个角度来尝试解决互斥问题(不再对每种思路再展开):

软件硬件
单标志法,双标志先检查法,双标志后检查法,Peterson算法中断屏蔽,TS/TSL指令,Swap/XCHG指令

最优秀的解决方法其实是信号量机制P操作 + V操作)

emmmm这部分408重难点,很难在小篇幅内说清楚。这里仅仅谈谈个人的理解,与考试无关:
 
首先,单标志和双标志法都采用了一种重要的思想:锁。
但为什么双标志法会出现致命缺陷?原因在于:原子性。
 
锁,简单来说就是把临界资源这个“小屋子”上锁,并拿走钥匙,使得其他进程无法进入这间屋子,即访问临界资源;等到它出来后,归还了钥匙,其他拿到钥匙的进程才得以进入。
这里实际上出现了一个致命的问题——检查是否上锁,和进入临界资源,是两个动作!!!
下面是在学习Java多线程时遇到的两个典例,很有助于理解“两个动作”的含义:
 在这里插入图片描述
因此,我们必须保证“检查”和“上锁”的原子性。

  • Peterson算法通过巧妙的“现代孔融让梨”避免了原子性问题
  • 硬件方法其实就是直接实现了原子性
  • PV操作使用开/关中断指令,使得本身就是原子操作

PV操作的经典问题,可以努力回想一下:

  • 生产者-消费者问题
  • 多生产者-多消费者问题
  • 吸烟者问题
  • 读者-写者问题
  • 哲学家进餐问题

 

同步

回忆一下你的学业生涯:幼儿园->小学->初中->高中->大学->…
这就是一种典型的同步问题,即保证一前一后的执行顺序,也可以叫做前驱关系——就像没有从小学结束直接跳级到大学,大学毕业后再去高考的道理。

上面提到的信号量机制(PV操作)也可以实现进程的同步,但和实现互斥的思路不太一样:

  • PV操作实现互斥:的思想
  • PV操作实现同步:用资源给资源的思想

 

死锁

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。(百度·百科)
 
这部分全是概念。

▶ 死锁产生的必要条件(缺一不可)

  • 互斥条件
  • 不剥夺条件
  • 请求和保持条件
  • 循环等待条件

▶ 死锁的处理策略

  1. 预防死锁:破坏4个必要条件其一即可
  2. 避免死锁:避免系统进入不安全状态(银行家算法)
  3. 死锁的检测和解除:允许死锁发生,系统负责检测出死锁并解除

 

代码

直观感受一下:

线程(进程)的执行不是一贯到底的,而是走走停停,以不可预知的速度向前推进(异步)

class MyRunnable1 implements Runnable{
    @Override
    public void run() {
        System.out.println("我是线程1  >_<");
    }
}

class MyRunnable2 implements Runnable{
    @Override
    public void run() {
        System.out.println("我是线程2  @_@");
    }
}

public class Demo {
    public static void main(String[] args) {
        while (true){
            Thread myThread1 = new Thread(new MyRunnable1());
            Thread myThread2 = new Thread(new MyRunnable2());
            myThread1.start();
            myThread2.start();
            System.out.println("我是主线程  ^o^");
        }
    }
}

在这里插入图片描述

 

 

 

 

 

 

这篇文章是一次OS的作业,要求为《理解并发》
因此,对于408来说这并不是一个完整的考点总结,对于初学者来说又会感到晦涩。
但是还是很高兴能有这么一次脱离课本和考试的机会,去理解操作系统,去感受计算机。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值