【避免进程死锁】银行家算法

一、概述

银行家算法(Banker’s Algorithm)是一个避免进程死锁的著名算法,由 Dijkstra 于 1965 年提出。本文为笔者的读书笔记,结构如下:

  • 死锁
  • 银行家算法
  • 例子展示
  • 补充:鸵鸟算法和实际系统中对死锁的处理方式

二、死锁

既然银行家算法就是为了解决进程死锁而出现的,那么首先我们应该先来了解下什么是死锁,以及死锁产生的4个条件。

2.1 什么是死锁

如果一组进程中的每一个进程都在等待仅由该组进程中的其他进程才能引发的事件,那仫该组进程就是死锁的。下图为一个进程死锁的例子:
在这里插入图片描述
图中有 4 个进程 P1、P2、P3、P4,它们分别持有资源 A、B、C、D,而 P1 的运行需要 B 资源,P2 的运行需要 C 资源,P3 的运行需要 D 资源,而 P4 的运行则是需要 A 资源,但是这些资源都被 P1~P4 这 4 个进程所分别持有,而它们在运行结束之前是不会主动释放自己所持有的资源的。在这种情况下就会造成一种僵持的局面,即为死锁。

2.2 死锁的4个必要条件

从上面的例子中,总结得出死锁的4个必要条件如下:

  • 互斥使用:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,那么请求进程只能等待,直到占有资源的进程用毕释放。
  • 请求和保持:指进程已经至少保持一个资源,但又提出了新的资源请求,而该资源又被其它进程占有,此时请求进程阻塞,但又对自己已获得的请求资源不放。
  • 不可抢占:指进程已经获得的资源,在未使用完之前,不可被剥夺,只能在使用完时由自己释放。
  • 循环等待:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{ P0, P1, P2, … , Pn }中的 P0 正在等待 P1 占用的资源;P1 正在等待 P2 占用的资源, … , Pn 正在等待 P0 占用的资源。

之所以特地强调是必要条件,是因为这 4 个条件之一不出现,系统就不会有死锁的情况发生。而避免死锁的策略,最为著名的就是银行家算法了;

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在C语言中实现避免死锁银行家算法可以通过以下步骤来实现: 1. 定义资源的最大需求量、已分配数量和可用资源数量。 ```c int max[NUMBER_OF_CUSTOMERS][NUMBER_OF_RESOURCES]; int allocation[NUMBER_OF_CUSTOMERS][NUMBER_OF_RESOURCES]; int available[NUMBER_OF_RESOURCES]; ``` 2. 实现安全性检查函数,判断当前状态是否安全。 ```c int isSafeState(int customer_id, int request[]) { // 模拟分配资源给该进程 for (int i = 0; i < NUMBER_OF_RESOURCES; i++) { available[i] -= request[i]; allocation[customer_id][i] += request[i]; } // 执行安全性检查 int work[NUMBER_OF_RESOURCES]; bool finish[NUMBER_OF_CUSTOMERS]; for (int i = 0; i < NUMBER_OF_RESOURCES; i++) { work[i] = available[i]; } memset(finish, false, sizeof(finish)); int count = 0; while (count < NUMBER_OF_CUSTOMERS) { bool found = false; for (int i = 0; i < NUMBER_OF_CUSTOMERS; i++) { if (!finish[i]) { bool canFinish = true; for (int j = 0; j < NUMBER_OF_RESOURCES; j++) { if (max[i][j] - allocation[i][j] > work[j]) { canFinish = false; break; } } if (canFinish) { // 进程可以完成,释放资源 finish[i] = true; for (int j = 0; j < NUMBER_OF_RESOURCES; j++) { work[j] += allocation[i][j]; } found = true; count++; } } } if (!found) { // 没有找到可完成的进程 break; } } // 恢复分配资源前的状态 for (int i = 0; i < NUMBER_OF_RESOURCES; i++) { available[i] += request[i]; allocation[customer_id][i] -= request[i]; } return count == NUMBER_OF_CUSTOMERS; } ``` 3. 实现资源请求函数,处理进程对资源的请求。 ```c bool requestResources(int customer_id, int request[]) { // 检查请求是否超过最大需求量 for (int i = 0; i < NUMBER_OF_RESOURCES; i++) { if (request[i] > max[customer_id][i] - allocation[customer_id][i]) { return false; } } // 检查请求是否超过可用资源数量 for (int i = 0; i < NUMBER_OF_RESOURCES; i++) { if (request[i] > available[i]) { return false; } } // 检查安全性并分配资源 if (isSafeState(customer_id, request)) { for (int i = 0; i < NUMBER_OF_RESOURCES; i++) { available[i] -= request[i]; allocation[customer_id][i] += request[i]; } return true; } else { return false; } } ``` 这样就可以通过调用`requestResources`函数来处理进程对资源的请求,并且使用`isSafeState`函数来判断当前状态是否安全。注意,上述代码只是一个简单的示例,实际应用中可能需要根据具体情况进行修改和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值