操作系统学习笔记-信号量及PV操作与进程互斥和消费者生产者问题

最近双改变了兴趣方向,正在coursera上学习操作系统这门课程

看到了关于多进程的互斥问题

大体就是说考虑到多进程的程序可能会共用共同的某一部分内容,这部分称为临界区

但是由于cpu的调度,如果有两个进程A,B

A在使用临界区的时候,由于种种原因被下CPU换成了B上CPU执行

但是这个时候A对临界区的操作还没有完成与保存,与此同时B又开始了对临界区的操作

这样势必会造成临界区数据的混乱

举个例子

银行的两个ATM取款机(进程AB)上同时在对一个银行账户操作(临界区)

ATM机的逻辑是这样的

ATM(count, val){//账户 取现金额

read(count) //读入账户数据

if(count>val){ //如果账户余额充足

count -=val;

}

write(count)//将剩余余额写入

}


比如说这个账户一共有5000元,首先一个人在A上取现2000,但是在取现后写入之前

另一个人在B上同样取现了1000,这个时候A就被暂停运行了,此时的count还没有被重写

B机器上还是读到有5000的余额,取后还剩4000,写入。

之后A继续执行,但是A中现在count的值是3000,再执行写入操作

于是最终账户的余额成了3000,而不是应该的2000。

为了解决这个问题,我们需要让进程在临界区的操作上互斥

也就是说同一时间只能有一个进程对其操作


然后学得一神奇的方式,叫做信号量法,发明者-----dijkstra,对就是那个最短路的dijkstra

他的解决方法是

设置两个函数原子函数(不可被中断)放在临界区的开始和结束

P()

临界区

V()


函数是这样的

count设置为1

P(s)

{

s.count--;

if(s.count<0){

表明已经有其他进程,所以本进程被设为阻塞状态,加入到等待队列s.queue中等待重新调度

}

}


V(s)

{

s.count++;

if(s.count<=0){

表示有进程在等待队列中

此时本进程已经结束对临界区的使用,所以可以唤醒等待队列中的一个进程

使其加入就绪队列

}

}


这样第一个申请使用临界区的进程可以直接使用

其他的就会被加入到等待队列中


这种方式完美的解决了互斥问题,并且相比其他的解决方案这个办法居然还可以解决生产消费者问题

太太太太厉害了


之后会写一下怎么用这个方式解决生产消费者问题


生产者消费者问题:

基本概念是有两个进程,对同一个缓冲区进行操作,一个生产者进程负责向缓冲区写入数据,消费者进程负责从缓冲区提取数据。

所以这样就有3个问题产生

1缓冲区不能同时被两个进程操作

2缓冲区满的时候,生产者不应该继续生产

3缓冲区空的时候,消费者也不应给继续消费


对于这个问题可以有个基本的解决方法就是

操作系统学习笔记-信号量及PV操作与进程互斥和消费者生产者问题_第1张图片

(图片来自 北京大学coursera操作系统网课)

简单来说就是依靠一个变量count来判断是否为空和满,如果不能执行操作则,睡眠,当可以执行的时候唤醒睡眠的状态。

但是这边有一个问题就是

如果消费者 判断count==0之后,即将睡眠的时候,被下cpu了,这个时候生产者最后count+1之后==1,所以知道之前有消费者睡眠了,需要唤醒

然后切换到消费者,这个时候消费者执行的是之前没有执行完的sleep代码,结果又回去睡眠了

但是之后生产者不再认为消费者处于睡眠状态,则出现了错误--消费者一睡不醒。


但是!PV操作解决了这个问题

大体代码如下


(图片来自 北京大学coursera操作系统网课)

简单来说就是将之前所说的PV操作的技术由1变成了具体的数,这样就天才的解决问题了!!

同时对缓冲区进行一下保护。

不过其中的开始的P操作的顺序不能变,因为如果 变了后

先占用缓冲区,然后发现没法写/读,去唤醒另一个进程,但是另一个进程首先要判断是不是有人在占用缓冲区,答案是yes,所以再回去原来的进程

然后就这样死住了......

好了,笔记结束。

你可能感兴趣的:(操作系统)