[操作系统居家课程讲义]ch05_进程同步

author: hxy
date: 2020.3.28

一个不幸的消息是,这一部分是需要大家写程序的。加油吧少年。

进程的同步

所谓 进程同步 ,简单说就是在程序(实际上是进程)并发执行的过程中,进程之间需要互相协作、共享资源时,对资源的一种保护和协调。

比如说,如果你在线看电影,你的在线播放器一般会用两个进程来实现这个功能(也可能用两个线程,这个后面再讲)。为什么呢?因为目前为止在我们的知识里,并发的单位是进程,如果用一个进程的话,就意味着当你的进程分配到一个时间片,它就必须一行一行代码的执行。你可能一个时间片在下载,然后时间片到了之后继续去就绪队列排队,到下一个时间片再播放,总之没办法同时进行。


但是如果用两个进程,那就意味着两个进程需要对同一块内存(存放电影缓存的那块内存)进行操作。假如你家网速比较慢,那就需要下载进程时刻告诉播放进程下载了多少电影了,否则就会出现错误。

与进程同步相关的还有一个概念,叫做 进程互斥 ,它属于进程同步的一种特殊情况,意思是多个进程需要对同一块数据的读写,但是它们不能同时进行操作。

比如你要在网上买火车票,那么这个订票系统里面就存在着一个互斥变量 —— 车票信息。极端情况下,比如在春运的时候,大家可能同时去抢一趟火车的票,在系统里就是有无数进程在同时去操作这个车票信息的变量。我们既要允许这种并发操作的行为,又只能一次让一个进程去修改车票信息,否则就可能会一票多卖了。

进程同步的实现,其实就是对共享变量(或者共享系统资源)进行保护。一个简单的方法就是给变量的状态设置一个信号灯,告诉进程们此时这个变量是否可以操作。

这个信号灯,在操作系统术语中称为 信号量

信号量

如果大家还记得一点点编程的知识,那么信号量该怎么实现的话应该心里会有一个答案 —— 那就是给需要保护的变量设置一个bool类型的变量flag就可以了。

如果是车票系统的那种情况,就是只有这个flag为True的时候,才说明这个座位目前没有人在申请购买,也才允许进程进行购买操作。否则的话你就只能一直刷新了。

同时也就意味着,如果一个人准备购买这张车票,那么他的购票进程的得给这个座位上个锁,也就是把flag设置为False,使得其他进程一看就知道这张票已经名花有主了。

根据这个思路,每个购票进程的程序就一目了然了:

while(flag == False) //如果座位有人在操作
{
  ; //循环体什么都不做,那就干等着刷票吧,万一正在操作的那个人没买呢
}

//这个座位现在没人在操作了
flag = False; //我先把座位锁定了,免得别人操作
buyTicket();  //购票行为

//如果你最终不要这个座位了
flag = True; //释放这个座位的操作权

但是在实际操作中这个方式是不可行的,因为flag的语言层次太高了。

在计算机中,cpu是一条一条指令执行的,而不是一行一行c语言程序。c语言是高级语言,一行c语言程序可能被编译成多行cpu指令。

这是因为,cpu虽然可以跟内存直接打交道,但是它在进行计算的时候,只能对cpu内部的寄存器进行操作。

回顾一下计算机组成原理,存储器的基本上是三级体系:寄存器(位于cpu里面) -> 内存(也就是存储器)-> 外存(硬盘、光盘、u盘等)。这三个级别离cpu越来越远,速度越来越慢,价格越来越低,容量越来越大。

寄存器的数量很有限,一个寄存器也只能存放几个字节的数据。cpu从内存中读 操作指令 (加减乘除等等), 然后把操作数从内存先复制到寄存器里,然后才能进行计算。

所以即使最简单的设置flag的操作,也需要进行三个步骤:

  1. 将flag从内存复制到寄存器;
  2. 设置flag的值;
  3. 把设置完的flag写回内存中。

而时间片可能在任何一个时刻结束,这就无法保证flag一定能够被成功设置。

因此,真正的flag机制无法在应用软件的层面实现,只能由操作系统来帮忙,只有操作系统才可以直接对底层硬件进行控制和操作。

这也是我们需要把flag这种标识符专门叫做信号量的原因,它是操作系统层面的特殊变量,有特殊的控制方法。

下一节学习信号量的几种实现方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值