同步与互斥

1.同步

        同步等待,例如,进程A和B需要进行通信,进程A选择先和进程B建立链接,那么必须等待B接受并回复,之后才能进行通信,这个过程就称为同步(同步通信);这里也可以引申出异步的概念,例如,进程A和B需要进行通信,进程A将数据发送到某一个地方(共享内存、消息队列),进程B有空了就去这个地方看一眼,有消息就取出,这个过程称为异步(异步通信)。类似于打电话和发短信,打电话必须对方接通你的电话,接下来才能进行通信;但是在发短信中,发送方只需要将短信发出就行了,接收方有空再去信箱查看。

2.互斥

        某一份资源,同时只允许一个进程访问(占用),当进程A对其访问时,进程B就必须等待进程A访问结束,才能访问。那么就称对该资源的访问是互斥地进行,该资源我们称为临界资源。

3.临界资源

        将一次只允许一个进程访问的资源称为临界资源,所以对临界资源的访问,必须是互斥的进行。

实现临界区互斥必须遵守的准则:

  • 空闲让进。临界区空闲就允许一个请求进入临界区的进程立即进入临界区。
  • 忙则等待。临界区非空闲,就不允许其他进程进入,这是临界资源的定义。
  • 有限等待。对于请求进入的进程,等待的时间必须是有限的,不等无限等待,否则会造成饥饿
  • 让权等待。当进程不能进入临界区时,应立即释放处理器,防止进程忙等。

        举个例子对这四个规则进行理解:你去奶茶店买奶茶,假设只有一名店员,同时只能为一位顾客服务(只能进行一杯奶茶的制作,制作完毕才能进行下一杯的制作),那么现在店员就是临界资源,而顾客就是申请访问临界区的进程。

举个例子对这四个规则进行理解:你去奶茶店买奶茶,假设只有一名店员,同时只能为一位顾客服务(只能进行一杯奶茶的制作,制作完毕才能进行下一杯的制作),那么现在店员就是临界资源,而顾客就是申请访问临界区的进程。

忙则等待:刚刚到奶茶店,发现人很多,那就只能排队等着,不允许插队。

空闲让进:前面排队的人都已经买完了,轮到你了,那么就开始和店员交谈,点餐。

有限等待:虽然奶茶店人很多,但是稍等一会总能排完。

让权等待:假设去奶茶店买奶茶,但是顾客很多需要排队,那么在排队期间需要人一直处于队伍中,不能抽身去做别的事情,一直忙于等待。

4.实现临界区互斥的基本方法

要实现临界区互斥,就是要完成临界区空闲状态和忙碌状态的转换,转换的时机是实现的核心。

4.1软件实现方法

        (1)单标志法。用一个公共的整型变量turn,表示当前允许进入临界区的进程编号。当turn=0,就让0号进程进入;当turn=1时,就让1号进程进入。并且在进程退出临界区时,就将turn赋值给另外一个号码。比如两个人用一台电脑玩文明6,开启热座模式;首先A占用电脑进行自己的回合,回合结束后,才允许B进行自己的回合。B操作结束,再让A操作,一直这样下去。

        该算法可以实现每次只允许一个进程进入临界区,但是两个进程必须交替访问。若一个进程不再进入,则另外一个进程之后也将无法再进入。当1号进程访问结束后,将turn设置为0,但是0号进程不想进入,此时turn标志将一直为0,那么1号进程也将无法进入,违背空闲让进原则。继续使用上面文明6的例子,假如B操作完了,但是A玩累了,来一句“我布响完辣”,那么B也将无法再继续进行游戏。

        (2)双标志先检查法。用一个数组flag[2],flag[0]=true,表示0号进程想进入临界区,flag[1]=false表示1号进程不想进入临界区。在0号进程想进入时,先去检查flag[1]是否为true,如果flag[1]为true,表示1号进行希望进入,那么就等待。如果flag[1]为false,就将自己的flag[0]设置为true,然后进入临界区,出来时,将flag[0]设置为false。

        这个方法有可能出现两个进程都将自己flag设置为true的情况,例如初始状态下进程0和1的flag都为false,然后此时都有进入临界区的想法,进程0先检查到flag[1]=false,在进程0设置还未开始前,进程1检查到flag[0]=false,然后进程0设置flag[0]=true,进程1设置flag[1]=true,就会出现两个进程都将自己的flag设置为true,违背忙着等待原则。这是因为检查和设置不是一气呵成的,于是后面就有方法,将检查和设置置为一体,不可中断。

        (3)双标志后检查。和算法二类似,只是将设置挪到了检查前面,这个算法虽然解决了两个进程同时访问临界区的问题,但是会引入一个新问题,就是两个进程都无法进入临界区。

        例如初始状态下,进程0和1的flag都为false,然后此时都有进入临界区的想法,此时进程0先设置flag[0]=true,然后在进程0检查之前,进程1设置flag[1]=true,此时进程0检查到flag[1]=true,以为临界区资源繁忙,于是等待,进程1检查到flag[0]=true,也以为临界区资源繁忙,于是等待,两个进程无限等待下去,出现饥饿现象,违背有限等待原则。像是两个孔融都让梨,互相谦让,结果两个孔融都吃不到,于是都饿死了。

        (4)Peterson算法。结合了单标志和双标志后检查算法,同时使用turn标志和flag[2]数组。

        以进程0访问临界区为例,对算法进行描述:
①.设置flag[0]=true以及turn=1,表示可以将访问机会谦让给进程1
②.检查进程1的flag[1]和turn的状态
③.若flag[1]=true且turn=1表示进程1可以进入临界区,那么进程0等待
④.若flag[1]=true且turn=1有一条不满足(此时turn必为0),说明进程0可以进入,继而访问临界区
⑤.访问结束,设置flag[0]=false,turn=1

        Peterson算法满足空闲让进,忙则等待,有限等待三个准则,但是不满足让权等待,当进程1在访问临界区时,进程0必须一直检查(周期性地)两个标志的值,才能知道临界区什么时候空闲。

4.2硬件实现方法

        (1)中断屏蔽方法。当一个进程正在访问临界区时,防止其他进程进入临界区的最简单的方法就会关中断,因为CPU只在发生中断时引起进程切换。
这会有几个问题:

  1. 限制CPU交替执行程序的能力,系统效率会降低
  2. 将关中断的能力给用户是很危险的,如果一个进程关中断后不再开中断,系统可能因此终止
  3. 不适用于多处理器系统,在一个CPU上关中断不影响另外的进程在其他CPU上执行相同的临界区代码(访问临界区)

        (2)硬件指令方法--TestAndSet指令。简称TS指令,这条指令是原子操作(不可被中断)。其功能是读出指定标志后将该标志设置为真。
为临界区资源设置一个标志lock,当lock=false(未上锁),当lock=true(已上锁)。当进程在进入临界区时,先用TS指令检查lock的值,若为false,则上锁并进入临界区;若为true,则阻塞等待。TS指令将检查和设置变味了一气呵成的原子操作,解决了前面软件算法中带来的问题。不过在阻塞等待过程中,需要一直循环使用TS指令检查,于是不能实现让权等待

        (3)硬件指令方法--Swap指令。这条指令也是原子操作(不可被中弄断),其功能是交换两个字的内容。先为每个进程设置一个key变量,初始为true,为临界区资源设置一个lock。当进程在进入临界区时,用Swap指令交换key和lock的值,再检查key的值:如果为true,代表临界区正在被访问,如果为false,表示临界区此时可以进入。

        总的来说,硬件实现方案就是把查询和设置置为一体。优点是:适用于任意数量的进程,支持多处理器系统,支持系统中有多个临界区。缺点是:等待的进程会一直处于忙等状态。

4.3互斥锁(mutex lock)

        互斥锁的两个操作:acquire()获取锁,release()释放锁。当一个进程访问临界资源时,就调用acquire()对临界区资源上锁,在退出时,调用release释放锁。当一个进程访问已上锁的临界区时,会被阻塞,直到锁被释放。acquire(),release()都是原子操作不可被中断,两个指令都是由硬件完成,也有忙等的缺点。互斥锁更像是上面硬件指令的一种描述的优化。

4.4信号量

        信号量只能被两个标准的原语(不可被中断)来访问:wait()和signal(),简写为P()和V(),或者P操作,V操作

        ①.整型信号量

        定义S表示资源数量,对其只有三种操作,初始化,wait,signal操作。

        wait操作先检查S的数量,如果不够(S≤0),就一直等待;否则S自减1,表示进入临界区,且临界区可访问的进程数减一。

        signal操作释放进程占用的资源,S自加1,表示退出临界区,且临界区可访问的进程数加一

        只要wait操作中信号量S一直不够(S≤0),就会不等循环测试,出现进程忙等。

        ②.记录型信号量

        记录型信号量增加了一个进程链表L,用于链接所有等待该资源的进程。当临界区空闲时,就允许链表中第一个进程访问临界区。

 5.总结

        通过一个标志或者多个标志记录临界区的状态,就可以基本实现空闲让进和忙则等待这两个准则,但是由于查询标记和设置标记的操作是可以被中断的(插入其他程序的指令),就会有概率导致前三个准则中有一个失效。

        所以使用硬件方法,将查询和设置置为一体,这样就可以满足前三个准则;由于不知道临界区什么时候空闲,所以需要进程对标志位一直进行查询,这样就会造成忙等.

        为了解决这个问题,使用一个队列将申请访问的进程挂起,将进程主动申请(一直查询标志),变为被动唤醒(只查询标志一次),当临界区空闲时,就通知队列中第一个进程,允许其进入临界区。

        将这些操作整合在一起,并由一个单独的进程进行管理,于是就有了管程的雏形。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值