银行家算法简易实现

这里写目录标题

  • 实验要求
  • 内容
  • 代码
    • main.cpp
    • myfunc.h
    • myfunc.cpp
  • 运行结果与分析

实验要求

程序可以针对不同进程的请求进行判断,并决定是否满足其需求。算法程序需要设计合理的数据结构,对资源情况、进程相关数据进行存储。

内容

随机生成数据, 并校验数据是否会产生死锁问题

实现银行家算法的核心: 安全性算法, 银行家算法的请求判断

打印每个线程的合法请求向量序列

打印银行家算法一次接受的请求向量序列

代码

main.cpp

#include <iostream>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <stdbool.h>
#include <set>
#include <vector>
#include "myfunc.h"// 5 个进程, 3类资源
#define NUM_RESOURCES 3
#define NUM_PROCESSES 5
#define MAX_RES_NUM 10#define Lock(x) pthread_mutex_lock(x)
#define UnLock(x) pthread_mutex_unlock(x)// 因为只有一个资源分配处理器, 所以各线程需要互斥地申请资源
pthread_mutex_t mutex;
// 银行家算法需要用到的数据结构
std::vector<int> available(NUM_RESOURCES);
std::vector<std::vector<int>>maximum(NUM_PROCESSES, std::vector<int>(NUM_RESOURCES));
std::vector<std::vector<int>>need(NUM_PROCESSES, std::vector<int>(NUM_RESOURCES));
std::vector<std::vector<int>>allocation(NUM_PROCESSES, std::vector<int>(NUM_RESOURCES));
/*** 初始化可用资源
*/
void init_resources() {for (int i = 0; i < NUM_RESOURCES; i++) {// [0, MAX_RES_NUM]available[i] = rand() % MAX_RES_NUM + 1;}
}
/*** 初始化每个线程对每个资源的最大需求, 不超过available* (虽然本人绝对这个maximum和need没多大区别)
*/
void init_maximum() {for (int i = 0; i < NUM_PROCESSES; i++) {for (int j = 0; j < NUM_RESOURCES; j++) {// [0, available[j]]maximum[i][j] = rand() % (available[j] + 1);}}
}/*** 初始化分配矩阵* 初值为0 
*/ 
void init_allocation() {for (int i = 0; i < NUM_PROCESSES; i++) {for (int j = 0; j < NUM_RESOURCES; j++) {allocation[i][j] = 0;}}
}// 初始化需求矩阵
void init_need() {for (int i = 0; i < NUM_PROCESSES; i++) {for (int j = 0; j < NUM_RESOURCES; j++) {need[i][j] = maximum[i][j] - allocation[i][j];}}
}/*** 安全性算法:* 在某时刻, 查看当前可用资源向量面对, need矩阵是否处于安全状态* 即是否可以找到一个安全序列, 安全序列并不是唯一的, * 能找出一个安全序列即可证明当前的available处于安全状态
*/
std::vector<int> process_ids(NUM_PROCESSES);
bool check_safe() {// work是当前可分配的资源向量std::vector<int> work(available);// 保存安全序列(有必要可以打印调试)std::vector<int> safe_seq;std::set<int> pids(process_ids.begin(), process_ids.end());for (int i = 0; i < process_ids.size(); i++) {// 检查need矩阵的每一行, 如果该行对应的需求向量 <= workfor (auto pid : pids) {if (need[pid] <= work) {safe_seq.push_back(pid);work += allocation[pid];pids.erase(pid);break;}}}// 如果能找到一个包含所有线程的安全序列if (safe_seq.size() == process_ids.size()) {return true;}return false;
}
// path保存每个线程的请求向量
std::vector<std::vector<std::vector<int>>> path(NUM_PROCESSES);
// schedule保存处理器调度请求向量的顺序和对应的线程编号
std::vector<std::pair<int, std::vector<int>>> schedule;
/*** 向处理器发起资源分配请求* 利用银行家算法处理请求与分配
*/
void* request_banker(void *arg) {int process_id = *((int *)arg);while (true) {Lock(&mutex);// 随机为当前进程构造请求向量std::vector<int> request(NUM_RESOURCES);for (int i = 0; i < NUM_RESOURCES; i++) {request[i] = rand() % (need[process_id][i] + 1);}// 请求的资源 > 当前剩余的资源, // 则让出cpu, 重新生成一个合理的reqif (request > available) {UnLock(&mutex);continue;}// 如果随机生成的req=0, 则重新生成if (request == std::vector<int>(NUM_RESOURCES, 0)) {UnLock(&mutex);continue;}// 给当前线程分配资源for (int i = 0; i < NUM_RESOURCES; i++) {available[i] -= request[i];allocation[process_id][i] += request[i];need[process_id][i] -= request[i];}// 如果给当前进程分配了它所请求的资源// 但是进入了不安全的状态, 则撤销此次分配资源if (!check_safe()) {for (int i = 0; i < NUM_RESOURCES; i++) {available[i] += request[i];allocation[process_id][i] -= request[i];need[process_id][i] += request[i];}// 如果该请求向量, 会使得当前状态进入不安全的状态// 则该请求非法, 让其它线程请求printf("Process %d is Waiting\n", process_id);print_vector(need[process_id]);UnLock(&mutex);continue;} // 调试信息保存path[process_id].push_back(request);schedule.push_back(std::make_pair(process_id, request));if (need[process_id] == std::vector<int>(NUM_RESOURCES, 0)) {printf("Process %d have completed.\n", process_id);// 一个线程完成他的操作后要释放占用的资源❗❗❗❗available += allocation[process_id];for (auto p : path[process_id]) {print_vector(p);}UnLock(&mutex);// break使得该线程结束break;} UnLock(&mutex);}
}
/*** 检查是否满足银行家算法的先决条件* 假设有n个线程, m种资源, 每种资源k[i](i=0, ..., m-1)个* 使得不产生死锁的充分条件为: 每种资源的总需求和 <= n + m[i] - 1* 即满足该条件一定不会发生死锁, 但是不满足只是可能会产生死锁* 这里所谓死锁为: * 当前未完成的线程集合中的任意一个线程的任意一个请求都不能被银行家算法接受* 从而导致每个线程都在持续的做无用的请求* 例如: 当前有n=3个线程, m=1种资源, 数量为3* 每个线程的需求need如下*   alloc need avail* A:  0    1    3* B:  0    1* C:  0    4* 线程A最多请求1个资源, 如果满足线程A, 则剩余2个资源, 不能满足其余的线程, 进入不安全状态, 拒绝此请求* 线程B最多请求1个资源, 如果满足线程B, 则剩余2个资源, 不能满足其余的线程, 进入不安全状态, 拒绝此请求* 线程C最少请求一个资源, 如果满足线程C, 则剩余2个资源, * 如果接受C的下限请求, 下一个状态也为不安全状态*   alloc need avail* A:  0    1    2* B:  0    1* C:  1    3* 最终会不会发生死锁, 取决于调度, 如果敲好串行的调度这些线程的请求, * 则肯定不会发生死锁, 否则有可能发生
*/
bool check_prerequisite() {std::vector<int> colsum(NUM_RESOURCES);for (int i = 0; i < NUM_PROCESSES; i++) {int rowsum = 0;for (int j = 0; j < NUM_RESOURCES; j++) {if (maximum[i] == std::vector<int>(NUM_PROCESSES, 0)) {return false;}colsum[j] += maximum[i][j];rowsum += maximum[i][j];}if (rowsum == 0) return false;}for (int i = 0; i < NUM_RESOURCES; i++) {if (NUM_PROCESSES + available[i] - 1 > colsum[i]) {return false;}}return true;
}
void init() {init_resources();init_maximum();init_allocation();init_need();
}int main() {std::vector<pthread_t> threads(NUM_PROCESSES);srand(time(NULL));// 初始化互斥锁pthread_mutex_init(&mutex, nullptr);// 随机生成可用资源// 直到生成的数据不会发生死锁init_resources();printf("prerequisite[] => ");for (int i = 0; i < NUM_RESOURCES; i++) {printf("%d ", NUM_PROCESSES + available[i]);}printf("\n");// 保证生成的数据不会有死锁问题do {init_maximum();} while (check_prerequisite());init_allocation();init_need();printf("available[] => ");print_vector(available);printf("need[][] => \n");for (int i = 0; i < NUM_PROCESSES; i++) {print_vector(need[i]);}// 创建进程线程for (int i = 0; i < NUM_PROCESSES; i++) {process_ids[i] = i;pthread_create(&threads[i], nullptr, request_banker, &process_ids[i]);}// 等待所有线程结束for (int i = 0; i < NUM_PROCESSES; i++) {pthread_join(threads[i], nullptr);}printf("A safe cpu schedule: \n");for (auto [pid, req] : schedule) {printf("Process %d : ", pid);print_vector(req);}// 销毁互斥锁pthread_mutex_destroy(&mutex);return 0;
}

myfunc.h

#ifndef MYFUNC_H
#define MYFUNC_H#include <vector>
#include <stdio.h>
// 声明一个函数,用于比较两个 vector<int> 是否相等
void print_vector(std::vector<int> v);
bool operator==(const std::vector<int>& v1, const std::vector<int>& v2);
bool operator<=(const std::vector<int>& v1, const std::vector<int>& v2);
bool operator<(const std::vector<int>& v1, const std::vector<int>& v2);
bool operator>(const std::vector<int>& v1, const std::vector<int>& v2);
std::vector<int>& operator+=(std::vector<int>& v1, const std::vector<int>& v2);
std::vector<int>& operator-=(std::vector<int>& v1, const std::vector<int>& v2);
std::vector<int> operator+(const std::vector<int>& v1, const std::vector<int>& v2);
#endif

myfunc.cpp

#include "myfunc.h"
void print_vector(std::vector<int> v) {if (v.empty()) return;printf("[");for (int i = 0; i < v.size(); i++) {if (i != v.size() - 1) {printf("%d, ", v[i]);} else {printf("%d]\n", v[i]);}}
}
bool operator==(const std::vector<int>& v1, const std::vector<int>& v2) {// 检查向量的大小是否相等if (v1.size() != v2.size()) {return false;}// 逐个比较向量的元素for (std::size_t i = 0; i < v1.size(); ++i) {if (v1[i] != v2[i]) {return false;}}return true;
}
bool operator<=(const std::vector<int>& v1, const std::vector<int>& v2) {// 检查向量的大小是否相等if (v1.size() != v2.size()) {return false;}// 逐个比较向量的元素for (std::size_t i = 0; i < v1.size(); ++i) {if (v1[i] > v2[i]) {return false;}}return true;
}
bool operator>(const std::vector<int>& v1, const std::vector<int>& v2) {return !(v1 <=v2);
}
bool operator<(const std::vector<int>& v1, const std::vector<int>& v2) {// 检查向量的大小是否相等if (v1.size() != v2.size()) {return false;}// 逐个比较向量的元素for (std::size_t i = 0; i < v1.size(); ++i) {if (v1[i] >= v2[i]) {return false;}}return true;
}
std::vector<int>& operator+=(std::vector<int>& v1, const std::vector<int>& v2) {if (v1.size() != v2.size()) {throw nullptr;}for (std::size_t i = 0; i < v1.size(); ++i) {v1[i] += v2[i];}return v1;
}
std::vector<int>& operator-=(std::vector<int>& v1, const std::vector<int>& v2) {if (v1.size() != v2.size()) {throw nullptr;}for (std::size_t i = 0; i < v1.size(); ++i) {v1[i] -= v2[i];}return v1;
}
std::vector<int> operator+(const std::vector<int>& v1, const std::vector<int>& v2) {if (v1.size() != v2.size()) {return std::vector<int>();}std::vector<int> result;result.reserve(v1.size());for (std::size_t i = 0; i < v1.size(); ++i) {result.push_back(v1[i] + v2[i]);}return result;
}

运行结果与分析

保证没有死锁的数据, 运行结果

available[] => [2, 7, 1]
need[][] =>
[0, 3, 1]
[1, 3, 0]
[0, 0, 1]
[0, 5, 1]
[1, 0, 1]
Process 0 have completed.
[0, 3, 0]
[0, 0, 1]
Process 1 have completed.
[1, 3, 0]
Process 2 have completed.
[0, 0, 1]
Process 4 have completed.
[1, 0, 0]
[0, 0, 1]
Process 3 have completed.
[0, 5, 0]
[0, 0, 1]
A safe cpu schedule: 
Process 0 : [0, 3, 0]
Process 0 : [0, 0, 1]
Process 1 : [1, 3, 0]
Process 2 : [0, 0, 1]
Process 4 : [1, 0, 0]
Process 4 : [0, 0, 1]
Process 3 : [0, 5, 0]
Process 3 : [0, 0, 1]

修改程序片段为

do {init_maximum();} while (!check_prerequisite());

生成可能会产生死锁的数据, 但是没有调度出死锁的情况

available[] => [9, 8, 7]
need[][] =>
[2, 3, 6]
[6, 2, 2]
[7, 7, 2]
[4, 0, 0]
[2, 5, 7]
Process 0 is Waiting
[2, 3, 6]
Process 0 have completed.
[1, 1, 2]
[0, 0, 2]
[0, 2, 2]
[1, 0, 0]
Process 1 have completed.
[6, 2, 1]
[0, 0, 1]
Process 3 have completed.
[1, 0, 0]
[2, 0, 0]
[1, 0, 0]
Process 4 have completed.
[2, 5, 6]
[0, 0, 1]
Process 2 have completed.
[1, 3, 1]
[5, 4, 0]
[0, 0, 1]
[1, 0, 0]
A safe cpu schedule:
Process 0 : [1, 1, 2]
Process 0 : [0, 0, 2]
Process 0 : [0, 2, 2]
Process 0 : [1, 0, 0]
Process 1 : [6, 2, 1]
Process 1 : [0, 0, 1]
Process 3 : [1, 0, 0]
Process 3 : [2, 0, 0]
Process 3 : [1, 0, 0]
Process 4 : [2, 5, 6]
Process 4 : [0, 0, 1]
Process 2 : [1, 3, 1]
Process 2 : [5, 4, 0]
Process 2 : [0, 0, 1]
Process 2 : [1, 0, 0]

生成可能会产生死锁的数据, 调度出死锁的情况

available[] => [10, 6, 8]
need[][] => 
[2, 0, 5]
[4, 6, 3]
[6, 2, 1]
[5, 3, 2]
[4, 4, 8]
Process 0 is Waiting
[2, 0, 5]
Process 4 is Waiting
[4, 4, 8]
Process 4 is Waiting
[2, 4, 8]
Process 0 have completed.
[1, 0, 4]
[0, 0, 1]
[1, 0, 0]
.....
此后程序阻塞...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/10415.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

做视频号小店,怎么找达人合作?这里有详细讲解

大家好&#xff0c;我是电商笨笨熊 做视频号小店是没有自然流量的&#xff0c;这点刚入驻的新玩家还不清楚&#xff1b; 因此很多老电商玩家们还想着继续拿其他平台动销自然流的玩法去做视频号&#xff1b; 只能说这种方式在视频号是完全行不通的&#xff0c;当下想要推广售…

设计模式2——原则篇:依赖倒转原则、单一职责原则、合成|聚合复用原则、开放-封闭原则、迪米特法则、里氏代换原则

设计模式2——设计原则篇 目录 一、依赖倒转原则 二、单一职责原则&#xff08;SRP&#xff09; 三、合成|聚合复用原则&#xff08;CARP&#xff09; 四、开放-封闭原则 五、迪米特法则&#xff08;LoD&#xff09; 六、里氏代换原则 七、接口隔离原则 八、总结 一、依赖…

Python-VBA函数之旅-setattr函数

目录 一、setattr函数的常见应用场景 二、setattr函数使用注意事项 三、如何用好setattr函数&#xff1f; 1、setattr函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://blog.csdn.net/ygb_1024?…

宏集Panorama SCADA软件获BACnet BTL认证

Panorama 获得BACnet BTL认证 建筑物的组件&#xff08;空调系统、照明传感器等&#xff09;能否使用共同通讯协议&#xff1f;这正是标准化 BACnet协议&#xff08;Building Automation and Control Networks&#xff09;所提供的功能。该协议旨在实现建筑物中各种设备和系统…

【TS】入门

创建项目 vscode自动编译ts 生成配置文件 tsc --init 然后发现终端也改变了&#xff1a;

SOCKET编程(3):相关结构体与函数

相关结构体与函数 sockaddr、sockaddr_in结构体 sockaddr和sockaddr_in详解 struct sockaddr共16字节&#xff0c;协议族(family)占2字节&#xff0c;IP地址和端口号在sa_data字符数组中 /* Structure describing a generic socket address. */ struct sockaddr {__SOCKADDR…

抓大鹅教程电脑端秒通关……

大家好&#xff0c;我是小黄。 最近抓大鹅小程序游戏很火&#xff0c;抓大鹅小游戏是由青岛蓝飞互娱科技股份有限公司开发并推出的一款休闲益智类三消游戏。在游戏中&#xff0c;玩家需要在特定的“购物篮子”背景下&#xff0c;找到三个相同的物品并将其消除。游戏的玩法简单…

社工库信息查询

此网站需要注册账号&#xff0c;新用户注册送3点券&#xff0c;每日签到可获得1.5点券。也可通过充值来查 我这里有方法可以利用缺陷来无限获取点券查人

Python 实战之量化交易

1. Python 实战之量化交易 2..Python量化交易实战-04.量化交易系统架构的设计 Python量化交易实战-04.量化交易系统架构的设计 - 知乎 3.Python量化交易实战-06.通过PythonAPI获取股票数据 Python量化交易实战-06.通过PythonAPI获取股票数据 - 知乎 3.Python量化交易实战…

程序员的归宿。。

大家好&#xff0c;我是瑶琴呀。 相信每个进入职场的人都考虑过自己的职业生涯规划&#xff0c;在不同的年龄段可能面临不同挑战&#xff0c;这点对于 35 的人应该更为感同身受。 对于程序员来说&#xff0c;大部分人的职业道路主要是下面三种&#xff1a;第一条&#xff0c;…

【Delphi 爬虫库 6】使用正则表达式提取猫眼电影排行榜top100

正则表达式库的简单介绍 正则表达式易于使用&#xff0c;功能强大&#xff0c;可用于复杂的搜索和替换以及基于模板的文本检查。这对于输入形式的用户输入验证特别有用-验证电子邮件地址等。您还可以从网页或文档中提取电话号码&#xff0c;邮政编码等&#xff0c;在日志文件中…

人生是旷野,不是轨道

最近看到一句话&#xff0c;很喜欢&#xff0c;分享一下。"人生是旷野&#xff0c;不是轨道"。人生不是固定的方程式&#xff0c;也没有唯一答案&#xff0c;没有谁生来就应该是什么样。别太被太多世俗观念束缚住手脚&#xff0c;每个人都有权利自由生长&#xff0c;…

用友畅捷通T+ keyEdit sql注入漏洞

产品介绍 畅捷通 T 是一款灵动&#xff0c;智慧&#xff0c;时尚的基于互联网时代开发的管理软件&#xff0c;主要针对中小型工贸与商贸企业&#xff0c;尤其适合有异地多组织机构&#xff08;多工厂&#xff0c;多仓库&#xff0c;多办事处&#xff0c;多经销商&#xff09;的…

朋友圈刷屏的粘土风格照片,你体验过了吗?

Remini 的粘土风格真的丑萌丑萌的&#xff01; 从去年“妙鸭相机”的走红&#xff0c;到今年Remini的刷屏&#xff0c;其实可以看出大众对于图片趣玩的兴趣非常大&#xff01; 一张普通的照片经过工具的处理&#xff0c;一下子变成新风格&#xff0c;让人眼前一亮。如果你也对…

GPT-SoVits:语音克隆,语音融合

首发网站 https://tianfeng.space 前言 零样本文本到语音&#xff08;TTS&#xff09;&#xff1a; 输入 5 秒的声音样本&#xff0c;即刻体验文本到语音转换。少样本 TTS&#xff1a; 仅需 1 分钟的训练数据即可微调模型&#xff0c;提升声音相似度和真实感。跨语言支持&…

信息收集方法合集 第1期

前言 在工作中&#xff0c;经常被问到某个文件怎么下载&#xff0c;原文来自哪里。索性把我知道的所有信息收集方法全部整理一遍&#xff0c;希望对大家有用&#xff0c;如果有帮助到你&#xff0c;非常荣幸&#xff0c;我会坚持分享我的学习、工作经验。 信息种类&#xff1…

如何用java编写一个猜数字游戏

我想到用c能编出一个猜数字游戏&#xff0c;于是我就尝试用java编写一个 代码如下&#xff1a; import java.util.Scanner; import java.util.Random;public class GuessTheNumber {public static void main(String[] args) {Scanner scanner new Scanner(System.in);Random…

云启未来:“云计算与网络运维精英交流群”与“独家资料”等你来探索“

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号&#xff1a;网络豆云计算学堂 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a; 网络豆的主页​​​​​ &#x1f680; 云计算与运维精英交流群诚邀您的加入…

搭建Docker私服镜像仓库Harbor

1、概述 Harbor是由VMware公司开源的企业级的Docker Registry管理项目&#xff0c;它包括权限管理(RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。 Harbor 的所有组件都在 Dcoker 中部署&#xff0c;所以 Harbor 可使用 Docker Compose 快速部署。 …

PermissionError: [Errno 13] Permission denied: ‘xx.xlsx‘的解决办法

我在转换文件的时候遇到这个报错&#xff0c;原因是文件名与已有文件名重复了 解决办法很简单&#xff0c;如下图把" " 里的名字换成不重复的&#xff0c;再次允许代码&#xff0c;会恢复正常