P代表消费资源,V代表产生资源
//空闲的资源
semaphore full = 0;
//生产者还能生产的资源数
semaphore empty = BUFFER_SIZE;
semaphore mutex = 1;
如果先调用P(mutex)再调用P(empty)和P(full)会有问题吗?
显然,生产者等待mutex锁的释放,而消费者却在等待生产者生产出来资源后,将自己唤醒.
我们将这种多个进程由于互相等待对方持有的 资源而造成的谁都无法执行的情况叫死锁
各自占有的资源和互相申请的资源形成了环路等待
缺点1: 需要预知未来,编程困难
缺点2: 许多资源分配后很长时间后才使用,资源利用率低
缺点: 仍然造成资源浪费
如果系统中的所有进程存在一个可完成的执行序列P1,…Pn,则称 系统处于安全状态
安全序列: 上面的执行序列P1,…Pn。
如何找?
Allocation表示当前进程已经分配的资源,Need表示当前进程还需要多少资源,Available表示当前剩余资源。
p0—>p4是四个进程,如何安排四个进程的执行序列,能够确保四个进程都能顺利执行完毕,而不会因为互相抢占资源,导致死锁发生呢?
这里答案选A,我们来验证一下:
A B C
5 3 2
A B C
7 6 3
后面同理,只要确保当前进程需要占用的资源数比剩余资源数多就行,这样当前进程拿到这些资源后,就可以顺序执行,执行完后释放掉自己占有的资源,这样剩余资源数会比一开始增加一些。然后再让需要占用更多资源数的进程去执行,以此往复即可。
把上面的推导过程写成算法,就是著名的银行家算法了。
核心在:
Need[i]<=Work---这里的Work就是Avaliable
如果剩余资源数多余当前需要的资源数,说明当前进程可以先执行。
我们可以利用银行家算法求出一个安全序列,但是银行家算法的复杂度比较高,因此系统代价大。
当有进程需要申请资源时,可以先调用银行家算法,计算是否会产生死锁,如果会的话,就阻止这次分配,
如上图所示: P0要申请(0,2,0),但是会发现分配后,剩余资源数无法满足任意一个进程的需求,因此无法求出安全序列,所以需要拒绝此次资源分配请求。
进程的回滚涉及很多方面,例如: 某个进程已经将部分数据写入磁盘了,此时你要回滚,这就很麻烦,还有很多其他的点需要考虑